首页 > 解决方案 > Angular 自定义 ControlValueAccessor 无法处理数组

问题描述

我有一个自定义的 ControlValueAccessor 来处理数组的值。

import { Component, forwardRef, Input } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: 'app-custom-control',
  templateUrl: './custom-control.component.html',
  styleUrls: ['./custom-control.component.scss'],
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => CustomControlComponent),
    multi: true,
  }]
})
export class CustomControlComponent implements ControlValueAccessor {

  disabled: boolean;

  @Input()
  value: string[] = [];

  constructor(
  ) { }


  addElement(text: string) {
    this.value.push(text);
    this.value = [].concat(this.value);
    this.emitValueChange();
  }

  removeElement(text: string) {
    this.value.splice(this.value.indexOf(text), 1);
    this.value = [].concat(this.value);
    this.emitValueChange();
  }

  emitValueChange(): void {
    this.onChange(this.value);
  }

  writeValue(obj: string[]): void {
    this.value = obj;
  }

  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }
  registerOnTouched(fn: any): void {
    this.onChange = fn;
  }


  onChange = (obj: any) => {
  };

  onTouched = () => {
  };
}

然后我有一个自定义验证器来检查是否至少存在一个元素。

export class CustomValidators {
    static minSelected(min: number = 1): ValidatorFn {
        return (control: AbstractControl): ValidationErrors | null => {
            if (control.value == null || !Array.isArray(control.value)) {
                // value is null or not an array
                return { minSelected: min, actualSelected: 0 };
            }
            else if (control.value.length < min) {
                // not enough
                return { minSelected: min, actualSelected: control.value.length };
            }
            else {
                // good to go
                return null;
            }
        }
    }
}

我在 FormGroup 中像这样使用它。

this.formGroup = this.formBuilder.group({
  events: new FormControl([], [CustomValidators.minSelected(1)]),
});

问题是,Angulars Forms 在初始化后没有检测到值的变化。我使用模板上的按钮和输入调用#addElement 和#removeElement 函数。当我对数组执行 console.log 时,我可以看到所有的变化。DOM 也会相应地更新。但是由于某种原因,当我更改数组的值时,不再调用验证器。因此不再拾取非法状态(如无元素/空数组),我无法正确验证表单。

标签: angularangular-reactive-forms

解决方案


我是一个白痴。

registerOnChange(fn: any): void {
  this.onChange = fn;
}
registerOnTouched(fn: any): void {
  this.onChange = fn;
}

敏锐的眼睛可能会注意到,我还将“触摸”处理程序绑定到更改处理程序。我假设 Angular 因此覆盖了“更改”处理程序,因为它在“触摸”处理程序之前被绑定。

愚蠢的错误,花了我几个小时。爱它。


推荐阅读