Angular2-自定义组件中的正向字段验证
我正在创建一个包含输入字段的自定义表单控件组件(电子邮件),我转发输入字段的值(正确完成),但也希望转发其错误 使用以下代码,当输入发生更改时,我成功地传递了字段的错误,但它没有正确地拾取初始错误 例如,即使视图已完全加载且值为“0”,此电子邮件字段仍将报告错误={'required':true}example@email.com”他说。开始在字段中键入,它将正确传递错误 所以我的问题是,在初始加载数据之后,如何传递错误? 注意:通过运行this.propagateChange(this.value)可以解决此问题;在DoCheck生命周期中,但我不喜欢它,我需要一些更高效的东西,但似乎没有其他钩子能做到这一点 以下是一个例子:Angular2-自定义组件中的正向字段验证,angular,angular2-forms,angular2-components,Angular,Angular2 Forms,Angular2 Components,我正在创建一个包含输入字段的自定义表单控件组件(电子邮件),我转发输入字段的值(正确完成),但也希望转发其错误 使用以下代码,当输入发生更改时,我成功地传递了字段的错误,但它没有正确地拾取初始错误 例如,即使视图已完全加载且值为“0”,此电子邮件字段仍将报告错误={'required':true}example@email.com”他说。开始在字段中键入,它将正确传递错误 所以我的问题是,在初始加载数据之后,如何传递错误? 注意:通过运行this.propagateChange(this.val
import {Component, forwardRef, Input, ViewChild} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR, NG_VALIDATORS, FormControl, NgModel} from '@angular/forms';
@Component({
selector: 'input-email',
template:`<form-group
[errors]="{'required':'Email required', 'email':'Invalid email format'}"
[info]="'Email*'"
>
<input
type = "email"
name = "email"
class = "form-control"
[(ngModel)] = "value"
placeholder = "{{placeholder}}"
(input)="onChange()"
email
required
#f = "ngModel"
>
{{f.errors | json}}
</form-group>`,
styleUrls: ['./email.component.css'],
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => InputEmailComponent), multi: true },
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => InputEmailComponent), multi: true }
]
})
export class InputEmailComponent implements ControlValueAccessor {
value:String = null;
@ViewChild('f') f:NgModel;
@Input()
placeholder:String = "Email";
propagateChange:any = (val) => {};
constructor() {}
onChange(){
this.propagateChange(this.value);
}
/**
* Write a passed NgValue value to the element.
*/
writeValue(value) {
if (value && this.value != value) {
this.value = value;
}
}
/**
* Set the function to be called
* when the control receives a change event.
* registers 'fn' that will be fired when changes are made
* this is how we emit the changes back to the form
*/
registerOnChange(fn) {
this.propagateChange = fn;
}
/**
* Set the function to be called
* when the control receives a touch event.
*/
registerOnTouched(fn) {}
/**
* Set the function to be called
* to validate if input has errors.
*/
validate(c: FormControl):any {
console.log('validate email');
return this.f.errors;
}
}
从'@angular/core'导入{Component,forwardRef,Input,ViewChild};
从'@angular/forms'导入{ControlValueAccessor,NG_VALUE_ACCESSOR,NG_VALIDATORS,FormControl,NgModel};
@组成部分({
选择器:“输入电子邮件”,
模板:`
{{f.errors | json}}
`,
样式URL:['./email.component.css'],
供应商:[
{provide:NG_VALUE_访问器,useExisting:forwardRef(()=>InputEmailComponent),multi:true},
{提供:NG_验证器,使用现有的:forwardRef(()=>InputEmailComponent),multi:true}
]
})
导出类InputEmailComponent实现ControlValueAccessor{
值:String=null;
@ViewChild('f')f:NgModel;
@输入()
占位符:String=“Email”;
传播更改:any=(val)=>{};
构造函数(){}
onChange(){
this.change(this.value);
}
/**
*将传递的NgValue值写入元素。
*/
writeValue(值){
if(value&&this.value!=值){
这个值=值;
}
}
/**
*设置要调用的函数
*当控件收到更改事件时。
*进行更改时将触发的寄存器“fn”
*这就是我们将更改发送回表单的方式
*/
注册变更(fn){
这一变化=fn;
}
/**
*设置要调用的函数
*当控件接收到触摸事件时。
*/
寄存器(fn){}
/**
*设置要调用的函数
*验证输入是否有错误。
*/
验证(c:FormControl):任何{
console.log(“验证电子邮件”);
返回此.f.错误;
}
}
使用NG\u异步\u验证器而不是NG\u验证器可以解决此问题,
我在这里发布了对我有效的解决方案:
import {Component, forwardRef, Input, ViewChild, KeyValueDiffers} from '@angular/core';
import {
ControlValueAccessor, NG_VALUE_ACCESSOR, FormControl, NgModel,
NG_ASYNC_VALIDATORS
} from '@angular/forms';
import {Observable} from "rxjs/Rx";
@Component({
selector: 'input-email',
templateUrl: './email.component.html',
styleUrls: ['./email.component.css'],
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => InputEmailComponent), multi: true },
{ provide: NG_ASYNC_VALIDATORS, useExisting: forwardRef(() => InputEmailComponent), multi: true }
]
})
export class InputEmailComponent implements ControlValueAccessor {
value:String = null;
differ: any;
@ViewChild('f') f:NgModel;
@Input()
info:String = "Email";
@Input()
placeholder:String = "Email";
propagateChange:any = (val) => {};
constructor(private differs: KeyValueDiffers) {
this.differ = differs.find({}).create(null);
}
onChange(){
this.propagateChange(this.value);
}
/**
* Write a passed NgValue value to the element.
*/
writeValue(value) {
if (value && this.value != value) {
this.value = value;
//setTimeout(()=>{this.propagateChange(this.value);},0)
}
}
/**
* Set the function to be called
* when the control receives a change event.
* registers 'fn' that will be fired when changes are made
* this is how we emit the changes back to the form
*/
registerOnChange(fn) {
this.propagateChange = fn;
}
/**
* Set the function to be called
* when the control receives a touch event.
*/
registerOnTouched(fn) {}
/**
* Set the function to be called
* to validate if input has errors.
*/
validate(c: FormControl):any {
return new Promise((resolve, reject) => {
Observable.of(c)
.debounceTime(300)
.switchMap(val => {
return Observable.of(val.errors);
})
.subscribe(result => {
console.log('RESOLVING ASYNC VALIDATOR: ' + JSON.stringify(result, null, 2));
resolve(result);
});
});
}
}
因为这个问题,我在采纳你的建议时遇到了麻烦 因此我选择了sync。验证程序如下所示:
export class MyInputComponent implements AfterViewInit, ControlValueAccessor, Validator {
...
@ViewChild('datePicker') public datePickerInput: NgbInputDatepicker;
...
ngAfterViewInit(): void {
this.ngControl = this.injector.get(NgControl);
// Force restart of validation
if (this.ngControl && this.ngControl.control) {
this.ngControl.control.updateValueAndValidity({
onlySelf: true
});
}
}
...
public validate(control: AbstractControl): ValidationErrors | null {
return this.datePickerInput ? this.datePickerInput.validate(control) : null;
}
我通过调用
ngAfterViewInit
中的onValidatorChange
回调(从Validator
界面)绕过了这个问题:
ngAfterViewInit(): void {
// Force the validation to trigger after the view has been initialised
// otherwise the initial value is not marked as invalid
if (this.onValidatorChange) {
// you need a setTimeout here to make the change after Angular's change detection
setTimeout(() => {
this.onValidatorChange();
this.cdr.markForCheck();
}, 0);
}
}
registerOnValidatorChange(fn: () => void): void {
this.onValidatorChange = fn
}