Ember Octane Glimmer组件@动作是如何调用的



这个问题与Ember Octane升级有关如何将值从组件传递到控制器

我很难将HBS表单中的值接收并分配到组件中,然后将其传递给控制器。有效的答案表明,我必须为每个表单字段创建一个@action函数。例如:

@action
changeNewPassword(ev) {
this.newPassword = ev.target.value;
}

但是,我不知道这些函数是在哪里或如何调用的,所以我不明白它们为什么工作。有人知道这些函数是如何调用的吗?

HBS 模板组件

<div class="middle-box text-center loginscreen animated fadeInDown">
<div>
<h3>Change Password</h3>
<form class="m-t" role="form" {{on "submit" this.changePassword}}>
{{#each this.errors as |error|}}
<div class="error-alert">{{error.detail}}</div>
{{/each}}
<div class="form-group">
<Input @type="password" class="form-control" placeholder="Old Password" @value={{this.oldPassword}} required="true" />
</div>
<div class="form-group">
<Input @type="password" class="form-control" placeholder="New Password" @value={{this.newPassword}} required="true" />
</div>
<div class="form-group">
<Input @type="password" class="form-control" placeholder="Confirm Password" @value={{this.confirmPassword}} required="true" />
</div>
<div>
<button type="submit" class="btn btn-primary block full-width m-b">Submit</button>
</div>
</form>
</div>
</div>

HBS 模板

<Clients::ChangePasswordForm @chgpwd={{this.model}} @changePassword={{action 'changePassword'}} @errors={{this.errors}} />

模板组件JS

import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
export default class ChangePasswordForm extends Component {
@tracked oldPassword;
@tracked newPassword;
@tracked confirmPassword;
@tracked errors = [];
@action
changeOldPassword(ev) {
this.oldPassword = ev.target.value;
}
@action
changeNewPassword(ev) {
this.newPassword = ev.target.value;
}
@action
changeConfirmPassword(ev) {
this.confirmPassword = ev.target.value;
}
@action
changePassword(ev) {
ev.preventDefault();
this.args.changePassword({
oldPassword: this.oldPassword,
newPassword: this.newPassword,
confirmPassword: this.confirmPassword
});
}
}

在Ember Octane中,您希望使用on修饰符来设置操作。

线路

<form class="m-t" role="form" {{on "submit" this.changePassword}}>

有效地为该表单元素的submit事件设置了一个事件监听器,该监听器将调用组件类上的changePassword函数(因为this.changePassword中的this意味着该函数是组件的本地函数(

调用此操作:

@action
changePassword(ev) {
ev.preventDefault();
this.args.changePassword({
oldPassword: this.oldPassword,
newPassword: this.newPassword,
confirmPassword: this.confirmPassword
});
}

changePassword操作依次调用changePassword函数,该函数在命名参数@changePassword下传递给组件

<Clients::ChangePasswordForm @chgpwd={{this.model}} @changePassword={{action 'changePassword'}} @errors={{this.errors}} />

现在,在你的Template Component JS中,你有另外三个动作

  1. changeOldPassword
  2. changeNewPassword
  3. changeConfirmPassword

据我从你发布的代码中所知,这些代码从未被使用过。它们看起来像是用于设置单向绑定输入的代码,但您使用的是内置的Input,它是Ember输入内置组件(使用输入值和@value之间的双向绑定(。需要注意的一个非常重要的区别是Input上的大写I。所有角括号组件都使用标题大小写(每个单独的单词以大写字母开头(。

你是不是做了这样的事情:

<input type="password" class="form-control" placeholder="New Password" value={{this.newPassword}} {{on 'input' this.changeNewPassword}} required="true">

然后,您将把this.changeNewPassword函数绑定到<input>元素的input事件(这是本机html<input>。使用您定义的changeNewPassword操作:

@action
changeNewPassword(ev) {
this.newPassword = ev.target.value;
}

您可以通过单向绑定使this.newPassword值与输入保持同步。

我认为您在示例中使用操作有两种方式。

  1. 通过{{on}}
<form class="m-t" role="form" {{on "submit" this.changePassword}}>

这个案例比较简单。当您在组件模板中执行this时,您引用的是组件的类,因此,当提交DOM事件发生在form元素中时,this.changePassword由模板调用。

您可以在{{on}}API文档中查看更多信息。

  1. 通过{{action}}
<Clients::ChangePasswordForm @chgpwd={{this.model}} @changePassword={{action 'changePassword'}} @errors={{this.errors}} />

在这种情况下,每当Clients::ChangePasswordForm内部触发@changePassword时,Ember都会在动作散列(经典语法(中搜索changePassword,或者在使用Clients::ChangePasswordForm的组件的类中搜索装饰方法(@action(。

您可以在{{action}}API文档中查看更多信息。

希望这有助于阐明行动机制。

对于额外的家庭作业,您可能需要查看有关操作的升级指南。

最新更新