【问题标题】:Angular reactive form validation with dynamically named controls具有动态命名控件的 Angular 反应式表单验证
【发布时间】:2018-11-20 19:52:30
【问题描述】:

在我使用响应式表单的 Angular 7 应用程序中,我正在基于 *ngFor 循环创建 input 元素,因此我最终得到了一个动态命名的输入:

<nav class="level" *ngFor="let work of workLeft">
    <input [formControlName]="work.abbrev">

这当然可以正常工作,但现在我正在尝试将验证错误消息添加到表单中,但我不确定如何“解决”该项目。例如,div 通常看起来像这样:

<div *ngIf="name.errors.required">

但我没有name,因为它是动态的work.abbrev 值。处理这个问题的正确方法是什么?

你可以在这里看到我的尝试:https://stackblitz.com/edit/angular-8zevc1

【问题讨论】:

  • workLeft 是某种FormArray 吗?如果没有,我建议它是一个。这样你就可以在你的组件类上创建一个getter 并在FormArray 上使用at API 来获取相关的FormControl/FormGroup
  • 不,它只是一个从 http web 服务返回的对象数组。但它不是类变量,它只是在生成表单数据的调用中创建的。
  • 我不确定您的评论有什么帮助,因为我问的是如何在 HTML 本身中处理它,我特别提到不想使用 FormArray。
  • 那是因为FormArray是这种场景下一般使用的东西。您想为workLeft 中的每个项目显示验证错误,它又是一个表单控件。另外,我认为您不需要保留任何映射来在任何地方跟踪索引和表单控件。这不是它的工作原理。
  • 好的,如果它是正确的方式,那就这样吧。你能告诉我 div 的 *ngIf 应该是什么样子吗?

标签: angular angular-reactive-forms angular7 angular2-form-validation


【解决方案1】:

我建议为此使用FormArray。使用FormArray,您的实现将如下所示:

对于组件类:

import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators, FormArray } from '@angular/forms';

export interface Data {
  abbrev: string;
  max: number;
}

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent {
  workForm: FormGroup;
  workLeft: any[];

  constructor(private fb: FormBuilder) {}

  ngOnInit () {

    this.workForm = this.fb.group({
      points: this.fb.array([])
    });

    this.fillFormArray();
  }

  private fakeWebserviceCall(): Data[] {
    return [
      { abbrev: 'foo', max: 12 },
      { abbrev: 'bar', max: 10 }
    ];
  }

  private fillFormArray() {
    this.workLeft = this.fakeWebserviceCall();
    const formControlsArray = this.workLeft.map(work => this.fb.control(work.abbrev, [Validators.min(0), Validators.max(work.max)]));
    formControlsArray.forEach(control => this.points.push(control));
    console.log(this.workForm.value);
  }

  get points(): FormArray {
    return <FormArray>this.workForm.get('points');
  }

  pointAt(index) {
    return (<FormArray>this.workForm.get('points')).at(index);
  }

}

在模板中:

<form [formGroup]="workForm">
    <div formArrayName="points">
        <div *ngFor="let point of points.controls; let i = index">
      {{ workLeft[i].abbrev }}: <input type="number" [formControlName]="i">
      <div *ngIf="pointAt(i).invalid && (pointAt(i).dirty || pointAt(i).touched)">
        The field is invalid
      </div>
    </div>
  </div>
</form>

这里有一个Sample StackBlitz 供您参考。

PS:我对您分享的 StackBlitz 进行了一些更新,包括 Angular 样式指南推荐的内容以及实际解决方案。希望对您有所帮助。

【讨论】:

  • 谢谢,感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-03
  • 2020-05-13
  • 2019-05-04
  • 1970-01-01
  • 2020-04-06
相关资源
最近更新 更多