自定义 angular2 表单输入组件,在组件内具有两种方式绑定和验证
Posted
技术标签:
【中文标题】自定义 angular2 表单输入组件,在组件内具有两种方式绑定和验证【英文标题】:Custom angular2 form input component with two way binding and validation inside a component 【发布时间】:2016-04-21 01:10:03 【问题描述】:有没有办法制作双向绑定输入组件,也可以在组件内部进行验证?
我想要实现的是拥有一个可以在我的表单中排列的组件,如下所示:
<form #f="ngForm">
<my-form-input [(inputModel)]="name" [inputField]="myFormInputName"></my-form-input>
<my-form-input [(inputModel)]="name2" [inputField]="myFormInputName2"></my-form-input>
...
<my-form-input [(inputModel)]="lastItem" [inputField]="lastItemName"></my-form-input>
</form>
我有以下设置,但不知道如何正确设置:
组件:
import Component,Input, Output,EventEmitter from 'angular2/core'
import FORM_DIRECTIVES from 'angular2/common';
@Component(
selector: 'my-form-input',
directives: [FORM_DIRECTIVES],
template:
`
<input type="text" class="form-control" id="i1" required [ngModel]="inputModel" (ngModelChange)="onChangeInput($event)" ngControl="ctrl" #ctrl="ngForm"/>
<p>"Is field valid? I would like to make some decisions here depending on that: "+ctrl.valid</p>
`
)
export class InputComponent
constructor();
@Input() inputField:string;
@Input() inputModel: Object;
@Output() inputModelChange = new EventEmitter();
onChangeInput(event)
this.inputModel=event;
this.inputModelChange.emit(event);
应用程序:
//our root app component
import Component from 'angular2/core'
import FORM_DIRECTIVES from 'angular2/common';
import InputComponent from './my.input'
@Component(
selector: 'my-app',
providers: [],
template: `
<div>
<p>Is there a way to make a custom 2 way binding form input component having also validation?</p>
<form #f="ngForm">
<my-form-input [(inputModel)]="name" [inputField]="myFormInputName"></my-form-input>
<p>name</p>
</form>
</div>
`,
directives: [InputComponent,FORM_DIRECTIVES]
)
export class App
constructor()
this.name = 'Angular2'
我还做了一个 Plunker 来说明我的问题:http://plnkr.co/edit/0vXjHbQmv7v7EKQcLWaa?p=preview
【问题讨论】:
请注意,Angular 文档不鼓励在组件中进行用户输入验证:“我们的组件是服务的大消费者。它们依赖服务来处理大多数杂务。它们不从服务器获取数据,他们不验证用户输入,他们不直接登录到控制台。他们将这些任务委托给服务。” --Arch doc。我不确定我是否完全同意这一点,但我会让你知道。 【参考方案1】:您可以将表单控件传递给您的组件,以便为输入创建一个专用控件。基于此新控件,当其valid
属性为false
时显示错误:
@Component(
selector: 'my-form-input',
directives: [FORM_DIRECTIVES],
template: `
<input type="text" class="form-control" id="i1"
[ngModel]="inputModel"
(ngModelChange)="onChangeInput($event)"
[ngFormControl]="formCtrl.controls[inputField]"/>
<p>Is field valid? I would like to make some decisions
here depending on that: formCtrl.controls[inputField].valid
</p>
`
)
export class InputComponent implements OnInit
@Input() inputField:string;
@Input() formCtrl;
@Input() inputModel: Object;
@Output() inputModelChange = new EventEmitter();
ngOnInit()
this.formCtrl.control.addControl(
this.inputField, new Control('', Validators.required));
onChangeInput(event)
this.inputModel=event;
this.inputModelChange.emit(event);
您需要使用addControl
方法使整个表单的状态与您在输入组件中创建的控件保持一致。
在您的情况下,您可以使用 ngControl
指令内联定义控件。我做了一些测试,但我无法让它以这种方式工作......
这是从父组件使用此组件的方法:
@Component(
selector: 'my-app',
template: `
<form #f="ngForm">
<my-form-input [(inputModel)]="name" [inputField]="myFormInputName" [formCtrl]="f"></my-form-input>
</form>
`,
directives: [ FORM_DIRECTIVES, InputComponent ]
)
export class AppComponent
刚开始还是检查问题。表单的全局状态未更新,出现以下错误:
Expression '
Valid : f.valid in AppComponent@1:24' has changed after it was checked. Previous value: '
Valid : true'. Current value: '
Valid : false'
要解决这个问题,请查看 Julien 基于 ChangeDetectorRef
类及其 detectChanges
方法的答案...
这是一个示例 plunkr:https://plnkr.co/edit/Z4uOUq2q4iXdpo0J6R1o?p=preview。
【讨论】:
确实有帮助。我对这个 enableProdMode 技巧有点困惑。什么情况下应该再次使用 enableDevMode?从 angular2 的角度来看是“DEV”还是从项目使用的角度来看是“DEV”? 我不认为启用 Prod 模式是解决此问题的正确方法...只是隐藏问题... 是的,你是对的。事实上,我会实现一个符合ngForm
/ ngControl
的组件。请参阅此答案:***.com/questions/34948961/…。这样我们就不应该再遇到问题了,因为我们将参与整个表单验证生命周期...
如果有人在这里绊倒并想知道为什么它不适用于select
,请仔细检查(ngModelChange)
是否绑定在select
,而不是option
。【参考方案2】:
Thierry 的回答部分不错,因为在启用 ProdMode 时,您只是在隐藏问题:您没有刷新组件。
您必须在表单组件初始化后调用“detectChange”:
export class AppComponent
constructor(private cdr: ChangeDetectorRef)
ngOnInit()
this.cdr.detectChanges();
【讨论】:
感谢您指出这一点,朱利安!我相应地更新了我的答案的 plunkr 在这里找到了这个解决方案:***.com/questions/34364880/…以上是关于自定义 angular2 表单输入组件,在组件内具有两种方式绑定和验证的主要内容,如果未能解决你的问题,请参考以下文章