typescript - La interfaz de usuario de Angular se congela al usar formArray con Autocompletado de Material dentro de Mat-table
Estoy usando un mat-table dentro de un popup. Dentro del mat-table habrá filas con mat-autocomplete. La cuestión es que necesito agregar filas dinámicamente. Estoy usando un formGroup dentro del cual hay un formArray.
este será el Modelo del FormGroup
{
formArray:
[
{
name:"someName",
material:"someMaterial",
quantity:5
},
{
name:"someName2",
material:"someMaterial",
quantity:5
},
]
}
Primero la cuadrícula estará vacía, pero cuando hago clic en un botón, se inserta un formGroup dentro del formArray (que es la fuente de datos para la cuadrícula). Pero cuando eso sucede, la interfaz de usuario se congela por completo y no puedo hacer nada.
aquí está el código del archivo HTML
<form [formGroup]="positionFormGroup">
<div class="card-body" style="height: 500px; overflow: auto;" >
<table class="full-width" style="overflow: scroll;" mat-table [dataSource]="this.positionFormGroup.get('positionInfos').value" formArrayName = "positionInfos">
<!-- Material Column -->
<ng-container matColumnDef="Material">
<th mat-header-cell *matHeaderCellDef class="text-center align-column">
<p [innerHTML]=" 'MachineCapacity.Grid_Label_IdMaterial' | translate"></p>
</th>
<td mat-cell *matCellDef="let data; let i = index" [formGroupName]="i">
{{data.idMaterial}}
<input type="text" formControlName="idMaterial" [matAutocomplete]="materialAuto">
<mat-autocomplete #materialAuto="matAutocomplete">
<mat-option *ngFor="let option of materialFilteredOptions | async" [value]="option.description"
class="auto-option">
{{option.description}}
</mat-option>
</mat-autocomplete>
</td>
</ng-container>
<!-- Quantity Column -->
<ng-container matColumnDef="Quantity">
<th mat-header-cell *matHeaderCellDef class="text-center align-column">
<p [innerHTML]=" 'MachineCapacity.Grid_Label_Quantity' | translate"></p>
</th>
<td mat-cell *matCellDef="let data">
{{data.quantity}}
</td>
</ng-container>
Puedo localizar el problema. Sucede debido a la referencia que estoy usando para el mat-auto complete. Funciona tanto cuando elimino la referencia matAutoComplete de la etiqueta input como cuando cambio el formControlName.
aquí está el código TS :
ngOnInit(): void {
// this.positionInfos = new FormArray([]);
this.positionFormGroup = this.formBuilder.group({
positionInfos: new FormArray([])
});
//this.positionFormGroup.
}
addMaterial(){
let data = {
rowID :'f',
position : 'f',
idMaterial:'f',
quantity: 'f',
isDeleted: 'f',
isActive:true
}
this.positionFormGroup.get('positionInfos')?.push(this.formBuilder.group(data))
//console.log( this.positionFormGroup.get('positionInfos').value)
}
Por favor, hazme saber si me estoy perdiendo de algo, gracias de antemano
Respuesta #1
No está relacionado con el problema de referencia y la interfaz de usuario no se está congelando en absoluto.
Estaba sucediendo debido a la detección de cambios, creo. Por eso sentimos una congelación de la interfaz de usuario.
Exactamente en este punto, [dataSource]="this.positionFormGroup.get('positionInfos').value" dispara la detección de cambios infinitas veces
No sé, por qué se estaba activando infinitas veces.
Ya tengo una respuesta para los grupos de formularios anidados.
html
<form [formGroup]="positionFormGroup" novalidate>
<table formArrayName="positionInfos">
<div *ngFor="let data of control; let i = index">
<div [formGroupName]="i">
<input type="text" formControlName="idMaterial" [matAutocomplete]="materialAuto">
<mat-autocomplete #materialAuto="matAutocomplete">
<mat-option *ngFor="let option of materialFilteredOptions | async" [value]="option.description">
{{option.description}}
</mat-option>
</mat-autocomplete>
</div>
</div>
</table>
</form>
ts
export class AppComponent {
positionFormGroup: FormGroup;
materialControl: FormControl = new FormControl('');
materialFilteredOptions: Observable<{ description: string; }[]>;
options = [
{ description: 'item1' },
{ description: 'item2' },
{ description: 'item3' },
{ description: 'item4' }
]
control: any;
constructor(private formBuilder: FormBuilder) {
}
ngOnInit(): void {
this.materialFilteredOptions = this.materialControl.valueChanges
.pipe(
startWith(''),
map(value => this.options)
);
this.positionFormGroup = this.formBuilder.group({
positionInfos: new FormArray([])
});
this.addMaterial();
this.control = this.getControls().controls;
}
addMaterial() {
(this.positionFormGroup.get('positionInfos') as FormArray).push(this.formBuilder.group({
rowID: '0',
position: '0',
idMaterial: 'item1',
quantity: 1,
isDeleted: false,
isActive: true
}));
}
confirm(){
console.log( this.positionFormGroup.get('positionInfos').value)
}
getControls(){
console.log( (this.positionFormGroup.get('positionInfos') as FormArray));
return (this.positionFormGroup.get('positionInfos') as FormArray);
}
