【问题标题】:Angular FormArray display validation errorsAngular FormArray 显示验证错误
【发布时间】:2019-02-06 21:33:36
【问题描述】:

我有在 FormBuilder 的帮助下构建的 Angular 表单。

Form 包含一个 FormArray,它包含用户想要的任意数量的字段。我已经为字段设置了验证器

this.fb.array([this.fb.control('', Validators.required)])

对于每个新的push 验证器都是相同的。

问题是我不知道如何访问特定字段的isValid 属性,因为它们通过[formControlName]="index"FormControl 绑定。

我尝试过这样做,但它似乎不起作用

<div *ngIf="array.at(index).invalid" class="alert alert-danger p-2">
</div>

其中array 是从父级传递的formArray.controls

更新 #1

有一个案例https://stackblitz.com/edit/angular-7ppkoh

【问题讨论】:

  • 请考虑创建一个堆栈闪电战。
  • @SiddharthAjmera 看看

标签: angular forms typescript validation angular2-form-validation


【解决方案1】:
creating form with formArray.

createForm() {
    this.studentForm = this.fb.group({
      name: [],
      id: [],
      hobbies: this.fb.array([])
    })
  }

  addHobbies() {
   const control = new FormControl(null, [Validators.required]);
   (<FormArray>this.studentForm.get('hobbies')).push(control);
  }

Printing error message to user

<form [formGroup]="studentForm" (submit)="saveStudent()">
    <input type="text" id="id" name="id" formControlName="id">
    <input type="text" id="name" name="name" formControlName="name">
    <div formArrayName="hobbies">
        <label>Hobbies</label>
        <button type="button" (click)="addHobbies()">Add Hobbies</button>
        <div *ngFor="let formControl of studentForm.get('hobbies')['controls']; let i = index">
            <input type="text" [formControlName]="i"> 
            <div *ngIf="!studentForm.get('hobbies')['controls'][i].valid && 
                        studentForm.get('hobbies')['controls'][i].errors?.required">
           <p>This field is required</p>
       </div>
        </div>
    </div>
    <button type="submit">Submit Student</button>
</form>

【讨论】:

  • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助,质量更高,更有可能吸引投票。
【解决方案2】:

我真的不认为这完全可以在模板上实现。这是因为要访问模板中 FormArray 控件的状态,您必须访问 this.formGroup.get('features').controls[i].invalid。但是由于get 返回一个AbstractControl 类型的实例,您将无法访问它上面的controls 数组。为此,您必须将从this.formGroup.get('features') 返回的任何内容类型转换为FormArray。而且我真的不认为这在模板上是可能的。

您必须在您的类中创建一个方法,该方法将根据索引返回控件的有效性。

因此,如果我们继续参考您的 stackblitz,例如,方法如下:

<form [formGroup]="formGroup">
  <div formArrayName="features">
    <div 
      class="row no-gutters form-group" 
      *ngFor="let feature of features.controls; let index = index; let last = last">
      <input 
        type="text" 
        class="form-control px-2 col" 
        [formControlName]="index" 
        title="feature" 
        required>

        IS Invalid - {{ getValidity(index) }}

      <div class="col-3 col-md-2 row no-gutters">
        <button 
          class="col btn btn-outline-danger" 
          (click)="removeFeature(index)">
          -
        </button>
        <button 
          class="col btn btn-success" 
          *ngIf="last" 
          (click)="addFeature()">
          +
        </button>
      </div>
    </div>
  </div>
</form>

在你的课堂上:

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

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

  constructor(
    private fb: FormBuilder,
  ) {}

  formGroup = this.fb.group({
    features: this.fb.array([this.fb.control('', Validators.required)])
  });

  get features(): FormArray {
    return this.formGroup.get('features') as FormArray;
  }

  addFeature(): void {
    this.features.push(this.fb.control('', Validators.required));
  }

  getValidity(i) {
    return (<FormArray>this.formGroup.get('features')).controls[i].invalid;
  }

  removeFeature(index): void {
    this.features.removeAt(index);
    console.log(this.features);
  }

}

更新

几个月前,我意识到在其中一种数据绑定语法中调用方法(即字符串插值 - {{ ... }}、属性绑定 - [propertyName]="methodName()" 或属性绑定 - [class.class-name]="methodName()"[style.styleName]="methodName()")是就性能而言,代价极高。

所以,你应该这样做:

{{ formGroup.controls['features'].controls[index].invalid }}

代替:

{{ getValidity(index) }}

这是一个更新的 Working Sample StackBlitz 供您参考。

如果您想了解更多信息,我强烈建议您查看此线程:

Angular Performance: DOM Event causes unnecessary function calls

希望这会有所帮助:)

【讨论】:

  • 谢谢。我是这样做的 get featureControl() { return (this.group.get('features') as FormArray).controls[this.index]; } 并且成功了!
  • 你打算如何在模板中传递this.index?只是好奇。
  • 我已经向您展示了我所拥有的改编版本。实际上, features 是一个额外的组件,它消耗来自父级的index。所以索引不会有任何问题
  • 哦。正确的。完美!
  • 您能否详细说明或提供一些关于调用具有数据绑定的方法的性能损失的文档?
【解决方案3】:

我在 Angular 8 中有这个例子。

当你这样做时在你的模板中。

<ng-container formArrayName="calibers">
        <ng-container *ngFor="let item of qualityForm.get('calibers')['controls']; let index = index" [formGroupName]="index.toString()">
          <ion-item>
            <ion-label position="floating">{{ getCaliberName(item) }}</ion-label>
            <ion-input formControlName="percentage" placeholder="Input Percentage" type="number" clearInput></ion-input>
            <ng-container *ngIf="item.get('percentage').hasError('required')">
              <span class="errorMsg">Input Percentage</span>
            </ng-container>
            <ng-container *ngIf="item.get('percentage').hasError('max')">
              <span class="errorMsg">Percentage cannot be greater than 100</span>
            </ng-container>
          </ion-item>
        </ng-container>
      </ng-container>

ngFor 中的那个项目对象将使您能够访问表单控件。要获得数组形式错误,您需要做的就是item.get('percentage').hasError('required')

【讨论】:

    【解决方案4】:

    如上回答使用

    feature.invalid 来自features.controls

    让您一次验证该控件内的所有元素。

    但是,如果您想验证特定元素,您可以使用以下代码:

    > feature.controls.controlname.invalid
    

    注意:我使用的是功能而不是功能

    【讨论】:

    • 如果您有一个包含多个控件的更复杂的 FormGroup,这是一个非常有用的区别
    【解决方案5】:

    你应该使用表单控件来实现这一点。

    <div *ngIf="formGroup.get('features').controls[i].controls.index.invalid && (formGroup.get('features').controls[i].controls.index.dirty || formGroup.get('features').controls[i].controls.index.touched)"                                          class="text-center error">
    <p [hidden]="!formGroup.get('features').controls[i].controls.index.errors.required">Index is required.</p>
    </div>

    【讨论】:

      【解决方案6】:

      在 ngFor 语句中,您定义了用于表单数组的每个控件的变量“feature”。

      *ngFor="let feature of features.controls; let index = index; let last = last"
      

      您可以使用该变量来获取该控件的无效状态。

      feature.invalid 
      

      这里是Stackblitz


      另外

      当您使用响应式表单时,您不需要 HTML 中的 required 属性。

      所以这个

      <input type="text" class="form-control px-2 col" [formControlName]="index" title="feature" required>
      

      可以

      <input type="text" class="form-control px-2 col" [formControlName]="index" title="feature">
      

      【讨论】:

        【解决方案7】:

        FormGroup 类有一个 get 方法,它返回给定键的 abstractControl。您在 formControlName 中使用的那个。

        这里是两个 Api 文档的链接:
        AbstractControl
        FormGroup

        <form [formGroup]="form">
          <input formControlName="name" type="text" />
          <div *ngIf="form.get('name').invalid">
            <p><Message you like to show/p>
          </div>
        </form>
        

        【讨论】:

          猜你喜欢
          • 2018-08-05
          • 1970-01-01
          • 2023-03-31
          • 2018-11-21
          • 1970-01-01
          • 2018-06-24
          • 2016-03-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多