Угловые ошибки проверки отображения 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
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>