【问题标题】:Angular - reactive forms with multipe checkboxes as a array touched validator issueAngular - 具有多个复选框的反应式表单作为数组触及验证器问题
【发布时间】:2022-01-11 16:07:23
【问题描述】:

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

代码

  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”总是错误的。无论我选择几个复选框还是不选择任何东西,'touched' 的值总是 false。

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

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

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

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

谢谢

【问题讨论】:

  • 在模板中使用this 毫无意义。你可以写*ngIf="form.controls['colors'].touched &amp;&amp; ..."

标签: javascript angular angular-reactive-forms


【解决方案1】:

更新stackblitz

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

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

  3. onCheckChange(event) {} 中添加了this.isTouched = true;

这是Github closed issue

touched property 反映了表单控件是否已经模糊,而不是更改。

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

您可以从以下位置更改您的代码:

<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">

【讨论】:

  • 但是如果你删除了触摸的条件,错误就会从你输入表格的那一刻开始显示。这不是我需要的。只有当用户触摸了这些复选框然后全部取消选中时,我才需要显示错误。
  • 我希望当用户进入表单页面时不会显示任何错误消息。只有在用户选中和取消选中复选框后,才会显示错误消息。这就是为什么我尝试使用 .touched
  • @David 我更新了我的答案,它应该像你期望的那样工作
  • 太棒了,谢谢!!!我喜欢你的解决方案:)
【解决方案2】:

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

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

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

好的,现在让我们将它附加到formarray:

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

【讨论】:

    猜你喜欢
    • 2022-01-11
    • 1970-01-01
    • 2019-02-21
    • 1970-01-01
    • 2019-05-04
    • 2018-01-23
    • 2019-07-10
    相关资源
    最近更新 更多