angular - Hvorfor er ikke mat-form-field redigerbar inne i denne FormArray?
Følgende skjema gjør nesten det det skal, bortsett fra at jeg ikke kan redigere noen mat-form-fields inni det. De er ikke deaktivert, det er bare ikke mulig å redigere dem.
Hva er grunnen til det?
Se: StackBlitz
Jeg ser ingen forskjell fra dette eksemplet 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 er faktisk relatert til ngFor-renderingsadferd.
For å være mer presis, hvis arrayet som brukes i ngFor endrer referansene til elementene i dette arrayet (og vi ikke har gitt en tilpasset trackBy-funksjon for å overstyre sammenligningen), vil Angular gjenkjenne disse endringene og gjengjengi visningen på nytt.
Angular-skjemaer kan ofte utløse AbstractControl.updateValueAndValidity-metoden for hele hierarkiet av kontroller.
FormControl -> parent -> FormGroup -> parent -> FormArray -> parent -> FormGroup
For FormGroup utløser det følgende metode:
_updateValue(): void { (this as{value: any}).value = this._reduceValue(); }
som i praksis oppretter et nytt objekt, altså {name: 'Alice'} Neste gang det utløses, vil det overskrive gjeldende verdi med en ny.
{name: 'Alice'} !== {name: 'Alice'}
Det er nettopp det Angular-standarddifferansen gjenkjenner i ngForOf-direktivet.
Du kan spørre?
Hvorfor ser jeg da ikke en forskjell på dette eksempelet på StackBlitz?
I det eksempelet er problemet fortsatt der, men det kan ikke sees ved første øyekast.
|username password
/\
click here(it works)
username password
/\
then click here(it doesn't since the dom was rerendered)
Forskjellen mellom ditt eksempel og eksempelet ovenfor er at du bruker materialkontroller, og utløseren AbstractControl.updateValueAndValidity skjer tidligere.
Så hva er løsningen?
1) Den nevnte trackBy-egenskapen
trackByFn(index) {
return index;
}
*ngFor="let data of form.controls.offers?.value; let i = index; trackBy: trackByFn"
Stackblitz-eksempel
2) Tildel this.form.controls.offers.value til komponentens egenskap og bruk den.
arr;
...
this.arr = this.form.controls.offers.value;
*ngFor="let data of arr; let i = index;"
Stackblitz-eksempel
