Angular - 具有多个复选框的反应式表单作为数组触及验证器问题

Angular - reactive forms with multipe checkboxes as a array touched validator issue

我正在尝试创建一个表单,用户可以在其中 select 多种颜色,然后提交表单。

代码

  colors: Array<any> = [
{ description: 'White', value: 'White' },
{ description: 'Black', value: 'Black' },
{ description: 'Blue', value: 'Blue' },
{ description: 'Green', value: 'Green' },
{ description: 'Yellow', value: 'Yellow' },
{ description: 'Red', value: 'Red' },
  ];

  constructor(
    private formBuilder: FormBuilder
  ) {
    this.fromInit();
  }

  ngOnInit(): void {}

  fromInit() {
    this.form = this.formBuilder.group({
      colors: this.formBuilder.array([], [Validators.required]),
    });
  }

  onCheckChange(event) {
    const formArray: FormArray = this.form.get(
      'colors'
    ) as FormArray;

    if (event.target.checked) {
      formArray.push(new FormControl(event.target.value));
    } else {
      let i: number = 0;

      formArray.controls.forEach((ctrl: FormControl) => {
        if (ctrl.value == event.target.value) {
          formArray.removeAt(i);
          return;
        }
        i++;
      });
    }
  }

  invalidColorsMessage() {
    if (this.form.controls['colors'].errors?.required)
      return "You must choose a color";
  }

HTML

      <div class="invalid-input-message"
       *ngIf="this.form.controls['colors'].touched &&
        this.form.controls['colors'].invalid">
    {{invalidColorsMessage()}}</div>

我遇到的问题是this.form.controls['colors']的属性'touched'总是错误的。无论我 select 几个复选框还是不 select 任何东西,'touched' 的值始终为 false。

我真的不明白为什么当我选中和取消选中复选框时它总是错误的。

预期的结果是每当有人选中和取消选中复选框并将所有内容留空时显示错误消息。

我想知道为什么 this.form.controls['colors'].touched 的值无论如何总是错误的。所以我尝试在网上搜索答案,但不幸的是没有找到解决方案。

这是复选框的演示:https://stackblitz.com/edit/angular-ivy-s8rc6j?file=src/app/app.component.html

谢谢

更新stackblitz:

  1. 设置isTouched = false;为全局变量

  2. 检查*ngIf=="isTouched && this.form.controls['colors'].invalid"

  3. onCheckChange(event) {}

    中添加了this.isTouched = true;

这是Github closed issue

touched property 反映表单控件是否已模糊,未更改。

触摸的表单永远不会 return 为真,因为模糊事件只发生在输入元素上。

您可以更改您的代码:

<div class="invalid-input-message" *ngIf="this.form.controls['colors'].touched && this.form.controls['colors'].invalid">

收件人:(删除 this.form.controls['colors'].touched 条件)

<div class="invalid-input-message" *ngIf="this.form.controls['colors'].invalid">

您可以使用自定义验证器,好东西,它可以重复使用!我们将它附加到 formarray 并检查数组的长度,如果长度至少为 1,我们 markAllAsTocuhed,因此您可以将 touched 保留在模板中。所以函数看起来像:

export function validate(ctrls: FormArray): ValidationErrors | null {
  if (ctrls.value.length) {
    ctrls.markAllAsTouched();
    return null;
  }
  return { notValid: true };
}

如果您希望它可重复使用,您可以将它放在服务中或其他组件可以导入它的地方。

好的,现在让我们将其附加到格式数组中:

fromInit() {
  this.form = this.formBuilder.group({
    colors: this.formBuilder.array([], { validators: validate }),
  });
}

然后在模板中检查是否存在错误以及是否已触及:

<div *ngIf="form.get('colors').hasError('notValid') && form.get('colors').touched">
  Please choose at least one
</div>

你的分叉 STACKBLITZ