angular - Varför går det inte att redigera mat-form-field inom denna FormArray?
Följande formulär gör nästan vad det ska göra förutom att jag inte kan redigera några mat-form-field inuti det. De är inte inaktiverade, det är bara inte möjligt att redigera dem.
Vad är anledningen till det?
Se: StackBlitz
Jag ser ingen skillnad jämfört med detta exempel på StackBlitz.
import {Component} from '@angular/core';
import {FormBuilder, FormGroup, FormArray, FormControl} from '@angular/forms';
@Component({
selector: 'form-field-label-example',
templateUrl: 'form-field-label-example.html',
styleUrls: ['form-field-label-example.css'],
})
export class FormFieldLabelExample {
public dataList = [
{name: 'Alice'},
{name: 'Bob'}
]
public form: FormGroup;
constructor(private _fb: FormBuilder) {
const formArray = this._fb.array([]);
for (const data of this.dataList) {
formArray.push(
this._fb.group({name: new FormControl(data.name)})
);
}
this.form = this._fb.group({
offers: formArray
});
}
}
<div>
<form [formGroup]="form">
<div formArrayName="offers" *ngFor="let data of form.controls.offers?.value; let i = index;">
<ng-container [formGroupName]="i">
<mat-form-field>
<input matInput placeholder="Name" formControlName="name">
</mat-form-field>
</ng-container>
</div>
</form>
<span *ngIf="form.dirty">DIRTY</span>
<mat-form-field>
<input matInput placeholder="Name">
</mat-form-field>
</div>
Svar #1
Det är faktiskt relaterat till ngFor-renderingsbeteende.
För att vara mer exakt, om arrayen som används i ngFor ändrar referenserna till elementen i denna array (och vi inte tillhandahöll en anpassad trackBy-funktion för att åsidosätta jämförelsen) kommer Angular att känna igen dessa förändringar och återrendera vyn.
Angular-formulär kan ofta utlösa AbstractControl.updateValueAndValidity-metoden för hela hierarkin av kontroller.
FormControl -> parent -> FormGroup -> parent -> FormArray -> parent -> FormGroup
För FormGroup utlöser det följande metod:
_updateValue(): void { (this as{value: any}).value = this._reduceValue(); }
vilket i princip skapar ett nytt objekt, dvs {name: 'Alice'} Nästa gång det utlöses kommer det att skriva över nuvarande värde med ett nytt.
{name: 'Alice'} !== {name: 'Alice'}
Det är exakt det som Angulars standarddiff identifierar i ngForOf-direktivet.
Du kan fråga?
Varför ser jag då ingen skillnad jämfört med det här exemplet på StackBlitz?
I det exemplet finns problemet fortfarande där men det kan inte ses vid första anblicken.
|username password
/\
click here(it works)
username password
/\
then click here(it doesn't since the dom was rerendered)
Skillnaden mellan ditt exempel och exemplet ovan är att du använder materialkontroller och att utlösaren av AbstractControl.updateValueAndValidity sker tidigare.
Så vad är lösningen?
1) Den tidigare nämnda trackBy-egenskapen
trackByFn(index) {
return index;
}
*ngFor="let data of form.controls.offers?.value; let i = index; trackBy: trackByFn"
Stackblitz-exempel
2) Tilldela this.form.controls.offers.value till komponentens egenskap och använd den.
arr;
...
this.arr = this.form.controls.offers.value;
*ngFor="let data of arr; let i = index;"
Stackblitz-exempel
