【问题标题】:setValidators in custom control without from reference in Angular自定义控件中的 setValidators 没有来自 Angular 中的引用
【发布时间】:2018-09-09 16:22:58
【问题描述】:

我创建了一个自定义输入控件。我不想创建任何自定义验证。我想使用默认要求,minLength,maxLength 等。我知道我可以这样做

this.form.controls["firstName"].setValidators([Validators.minLength(1), Validators.maxLength(30)]);

但我无法从父组件发送表单引用。如何在文本框组件中使用 setValidator。

// input-box.component.ts    
    import { Component, Input, forwardRef } from '@angular/core';
    import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';


    @Component({
      selector: 'app-input-box',
      template:`<label >{{inputdata.label}}</label><br>
      <input type="text" required #textBox [value]="textValue" (keyup)="onChange($event.target.value)" />`,
      styleUrls: ['./input-box.component.less'],
      providers: [
        {
          provide: NG_VALUE_ACCESSOR,
          useExisting: forwardRef(() => InputBoxComponent),
          multi: true
        },
        /*{
          provide: NG_VALIDATORS,
          useExisting: forwardRef(() => InputBoxComponent),
          multi: true,
        }*/]
    })
    export class InputBoxComponent implements ControlValueAccessor {
      @Input() inputdata: any;
      private textValue: any = '';

      onChange(value) {
        this.textValue = value;
        this.propagrateChange(value);
      }

      private propagrateChange = (_: any) => { };

      writeValue(value: any) {
        if (this.inputdata.value) {
          this.textValue = this.inputdata.value;
          this.propagrateChange(this.inputdata.value);
        }

      }

      registerOnChange(fn: (value: any) => any) {
        this.propagrateChange = fn;
      }


      registerOnTouched() { }
    }

在不同的组件中使用

<app-input-box  name="textBoxParent_{{index}}"  [inputdata]="goaldata"  ngModel ></app-input-box>

【问题讨论】:

    标签: angular angular5 angular2-forms angular4-forms angular-validation


    【解决方案1】:

    如果你想在一个想要实现ControlValueAccessor 的类中访问FormControl,你必须改变你通常的实现。您不能在 providers 数组中将类注册为 ControlValueAccessor 并在构造函数中注入 FormControl。因为 FormControl 会尝试注入你的类,而你会尝试注入控件,这会创建一个循环依赖。

    所以你需要做的改变如下:

    1. providers 数组中删除NG_VALUE_ACCESSORNG_VALIDATORS
    2. 在构造函数中注入NgControl,并设置控件的ControlValueAccessor和Validators。

      constructor(@Self() ngControl: NgControl) { 
         ngControl.valueAccessor = this;
         ngControl.setValidators([Validators.minLength(1), Validators.maxLength(30)]
         ngControl.updateValueAndValidity()
      }
      

    如果您想保留自定义表单组件的使用者指定的验证器,您需要将构造函数修改为:

    constructor(@Self() ngControl: NgControl) { 
      const control = ngControl.control;
    
      let myValidators = [Validators.required, Validators.minLength(5)];
      let validators = control.validator
      ? [control.validator, ...myValidators]
      : myValidators;
    
      control.setValidators(validators)
      control.updateValueAndValidity();
    }
    

    查看 Kara Erickson(角核心)在 AngularConnect 2017 上解释的整个过程。Link

    【讨论】:

    • @TomaszKula,我观看了该视频,它解决了 OP 的用例而无需自定义验证,但有没有办法也使用自定义表单控件类中定义的自定义验证方法?
    【解决方案2】:

    您也可以保留您的代码,只需从Injector 获取NgControl,如下所示:

    constructor(private injector: Injector) { 
    }
    
    public ngAfterViewInit(): void {
      const ngControl = this.injector.get(NgControl);
      const control = ngControl.control;
      // Do whatever you want with validators now:
      control.setValidators(validators)
      control.updateValueAndValidity();
    }
    

    您需要使用生命周期挂钩ngAfterViewInit,否则控件将不可用。

    像这样你可以跳过循环依赖的问题,你可以将NG_VALUE_ACCESSORNG_VALIDATORS留在providers数组中。


    a related question about injecting NgControl here
    建议使用注射器in the answer from @yurzui here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-26
      • 2017-07-02
      • 2019-06-13
      • 2017-11-15
      • 1970-01-01
      • 2016-04-16
      • 1970-01-01
      相关资源
      最近更新 更多