Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/31.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular2-自定义组件中的正向字段验证_Angular_Angular2 Forms_Angular2 Components - Fatal编程技术网

Angular2-自定义组件中的正向字段验证

Angular2-自定义组件中的正向字段验证,angular,angular2-forms,angular2-components,Angular,Angular2 Forms,Angular2 Components,我正在创建一个包含输入字段的自定义表单控件组件(电子邮件),我转发输入字段的值(正确完成),但也希望转发其错误 使用以下代码,当输入发生更改时,我成功地传递了字段的错误,但它没有正确地拾取初始错误 例如,即使视图已完全加载且值为“0”,此电子邮件字段仍将报告错误={'required':true}example@email.com”他说。开始在字段中键入,它将正确传递错误 所以我的问题是,在初始加载数据之后,如何传递错误? 注意:通过运行this.propagateChange(this.val

我正在创建一个包含输入字段的自定义表单控件组件(电子邮件),我转发输入字段的值(正确完成),但也希望转发其错误

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

例如,即使视图已完全加载且值为“0”,此电子邮件字段仍将报告错误={'required':true}example@email.com”他说。开始在字段中键入,它将正确传递错误

所以我的问题是,在初始加载数据之后,如何传递错误?

注意:通过运行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;

  }
}
从'@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
  }