Угловые ошибки проверки отображения FormArray

У меня есть угловая форма, которая построена с помощью FormBuilder.

Форма содержит FormArray, который имеет столько полей, сколько хочет пользователь. Я установил валидатор для полей

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

и для каждого нового push валидатор тот же.

Проблема в том, что я не знаю, как получить доступ к конкретному полю isValid собственности, так как они связаны с FormControl с помощью [formControlName]="index",

Я пытался сделать это таким образом, но это не похоже на работу

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

куда array это formArray.controls перешел от родителя.

Обновление № 1

Есть дело https://stackblitz.com/edit/angular-7ppkoh

2 ответа

Решение

Я не думаю, что это было бы возможно полностью на шаблоне. Это связано с тем, что для доступа к состоянию элемента управления FormArray в вашем шаблоне вам потребуется this.formGroup.get('features').controls[i].invalid, Но с тех пор get возвращает экземпляр типа AbstractControlу вас не будет доступа к controls массив на это. Для этого вам нужно будет ввести все, что возвращается this.formGroup.get('features') в FormArray, И я не думаю, что это было бы возможно на шаблоне.

Вам нужно будет создать метод в вашем классе, который будет возвращать валидность элемента управления на основе индекса.

Поэтому, если мы продолжим ссылаться на ваш стек, например, вот как:

<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);
  }

}

Вот StackBlitz для вашей ссылки.

У меня есть этот пример в 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')

В операторе ngFor вы определяете переменную "feature", которая будет использоваться для каждого элемента управления массива формы.

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

Вы можете использовать эту переменную, чтобы получить недопустимый статус этого элемента управления.

feature.invalid 

Вот Штаблиц


Дополнительно

Вам не нужен обязательный атрибут в HTML, когда вы используете реактивные формы.

Так это

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

Вы должны использовать элементы управления формы, чтобы добиться этого резко.

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

Класс 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>

Как указано выше, ответьте, используя

feature.invalid из features.controls

позволяют проверить все элементы внутри этого элемента управления за один раз.

Однако, если вы хотите проверить конкретный элемент, вы можете выполнить код:

> feature.controls.controlname.invalid

Примечание: я использую функцию, а не функции

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>
Другие вопросы по тегам