2017-01-29 69 views
0

我创建一个自定义表单控制组件(电子邮件)转发字段验证包含输入字段,我转发输入字段(做得正确)的价值,但也希望着它的错误Angular2 - 自定义组件

使用下面的代码,当输入发生变化时,我成功地传递了字段的错误,但它没有正确拾取初始错误。

例如即使在视图完全加载并且将“[email protected]”的值传递给它时,该电子邮件字段仍然会报告errors = {'required':true}。开始在字段中键入它会正确地传递错误。

所以我的问题是,我怎么能传递错误数据的初始加载后?

注意:通过运行this.propagateChange(this.value)可以解决问题。在DoCheck生命周期,但我不喜欢它,我需要的东西是更有效,但没有其他挂钩,似乎这样的伎俩。

这里是例子:

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; 

    } 
} 

回答

1

这个问题可以通过使用NG_ASYNC_VALIDATORS代替NG_VALIDATORS, 我张贴在这里为我工作的解决方案来解决:

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); 
     }); 
    }); 

    } 
}