我试图找出为ngModel实现自定义验证器逻辑的最简单方法。我有一个预定义的模型(接口),它存储当前数据,所以我不想处理新的FormGroup / FormControl(模型驱动)方法。
如果我已经拥有了我需要的所有数据,为什么要与FormControls构建完全相同的模式?
这是我的代码(https://plnkr.co/edit/fPEdbMihRSVqQ5LZYBHO):
-sgn(y.compareTo(x))
如您所见,我可以快速打开/关闭编辑模式,我可以直接编辑我的数据。
我的问题是如何直接从我的组件管理ngModel的ng-valid / ng-invalid状态?这背后的想法包含多个要点:
答案 0 :(得分:7)
最后我想出了办法。我认为这是最简单的。 我还更新了plunker:https://plnkr.co/edit/fPEdbMihRSVqQ5LZYBHO
让我们一步一步看。
1 - 创建一个简单的最小指令,实现Validator接口 - 与往常一样 - 但不要编写任何验证逻辑。而是提供函数类型的Input()字段 - 与选择器同名。这将允许我们在此验证器之外实现真正的逻辑。在validate(...)函数内部只调用外部Input()函数。
import { Directive, forwardRef, Input } from '@angular/core';
import { AbstractControl, NG_VALIDATORS, Validator, ValidatorFn } from '@angular/forms';
@Directive({
selector: '[myvalidator][ngModel],[myvalidator][ngFormControl]',
providers: [{
multi: true,
provide: NG_VALIDATORS,
useExisting: forwardRef(() => MyValidator)
}]
})
export class MyValidator implements Validator {
@Input() myvalidator:ValidatorFn; //same name as the selector
validate(control: AbstractControl):{ [key: string]: any; } {
return this.myvalidator(control);
}
}
2 - 要使用自定义验证器,只需将其导入并添加到组件的指令数组中。在模板标记中使用它像任何其他指令:
<input type="text" name="title" [(ngModel)]="data.title" [myvalidator]="validateTitle()">
诀窍就在这里。传递给验证器的Input()函数的值是函数调用 - 它将返回验证器函数。这是:
validateTitle() {
return <ValidatorFn>((control:FormControl) => {
//implement a custom validation logic here.
//the 'this' points the component instance here thanks to the arrow syntax.
return null; //null means: no error.
});
以上所有与官方Angular2验证器完全兼容 - 必需,模式等 - 因此我们的自定义验证器可以合并而无需任何进一步的技巧。
修改强> 如果在组件的构造函数中为每个验证创建局部变量,则可以实现更简单有效的方法:
private validateTitle:ValidatorFn;
constructor() {
this.validateTitle = (control:FormControl) => {
//implement a custom validation logic here.
//the 'this' points the component instance here thanks to the arrow syntax.
return null; //null means: no error.
};
}
使用这种方法,我们只创建一次ValidatorFn函数,而不是每个验证请求。 1个函数调用eleminated:validateTitle()。所以在模板中我们可以绑定变量:
<input type="text" name="title" [(ngModel)]="data.title" [myvalidator]="validateTitle">
答案 1 :(得分:0)
如果您不想使用一次性模板驱动的表单验证指令:
使输入可访问
#receiverInput="ngModel"
绑定控制器
@ViewChild(NgModel, { static: true }) receiverInput: NgModel;
验证
this.receiverInput.control.setValidators((control: AbstractControl) => {
if (!this.receiver.kundenNr) {
// invalid
return { receiver: false };
}
// valid
return null;
});