Angular 中没有引用的自定义控件中的 setValidators

setValidators in custom control without from reference in Angular

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

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>

如果您想访问 class 中的 FormControl,而该 class 想要实现 ControlValueAccessor,您必须更改通常的实现方式。您不能在提供程序数组中将 class 注册为 ControlValueAccessor 并在构造函数中注入 FormControl。因为 FormControl 将尝试注入您的 class,而您将尝试注入控件,这将创建循环依赖。

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

  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(angular 核心)在 AngularConnect 2017 上解释的整个过程。Link

您也可以保持代码不变,只需从 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 数组中。



建议使用注射器