Reputation: 503
I am trying to create a Dynamic formArray inside the array, but I am getting an error
Property 'controls' does not exist on type 'AbstractControl<any, any>
I create a project on Stackblitz
https://stackblitz.com/edit/reactive-form-validation-angular-15-klcsph
I just want to resolve the error
Upvotes: 1
Views: 134
Reputation: 58099
Another approach: I like only use a "getter" for the formArrays (the inner it's not a getter because we need the "index" of the row, but I hope the idea was clear)
get grid(): FormArray {
return this.myForm.get('grid') as FormArray;
}
getRow(index:number)
{
return this.grid.at(index) as FormArray
}
<form [formGroup]="myForm">
<div formArrayName="grid">
<div *ngFor="let row of grid.controls; let i = index" [formArrayName]="i" >
<div *ngFor="let cell of getRow(i).controls; let j = index">
<input [formControlName]="j"/>
</div>
<button type="button" (click)="removeRow(i)">Remove Row</button>
</div>
</div>
<button type="button" (click)="addRow()">Add Row</button>
<button type="button" (click)="addColumn()">Add Column</button>
</form>
BTW, the function addRow should becomes like
addRow() {
const cells=this.grid.controls.length?
this.getRow(0).controls.map(_=>''):
[]
this.grid.push(this.fb.array(cells));
}
In case we can only mannagge the "grid", (that's, the grid don't belong to any formGroup) we can use another "getter" for the formControls
controls(row:number,col:number)
{
return this.grid.get(row+'.'+col) as FormControl
}
In this case simply (see that the're no FormGroup)
<div *ngFor="let row of grid.controls; let i = index" >
<div
*ngFor="let cell of getRow2(i).controls; let j = index"
>
<input [formControl]="controls(i,j)"/>
</div>
<button type="button" (click)="grid2.removeAt(i)">Remove Row</button>
</div>
A stackblitz with the two approaches
Upvotes: 0
Reputation: 58492
Below are the changes made to make it work.
as FormArray
or <FormArray>
to give typing to the controls and formArrays.code
// Getters for easy access to FormArrays
get gridControls(): FormArray[] {
return (<FormArray>this.myForm.get('grid')).controls as FormArray[];
}
// Getters for easy access to FormArrays
get grid(): FormArray {
return this.myForm.get('grid') as FormArray;
}
getFormArrayControls(input: FormArray): FormControl[] {
return input.controls as FormControl[];
}
grid.controls
to getGridControls
to ensure that the right types were sent to the *ngFor
this also got rid of many errors.html
...
<div *ngFor="let row of gridControls; let i = index" [formGroupName]="i">
<div
*ngFor="let cell of getFormArrayControls(row); let j = index"
[formGroupName]="j"
>
<input [formControl]="cell" />
</div>
<button type="button" (click)="removeRow(i)">Remove Row</button>
</div>
...
ts
import { Component, OnInit } from '@angular/core';
import {
FormBuilder,
FormGroup,
FormArray,
Validators,
FormControl,
} from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
myForm: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.myForm = this.fb.group({
grid: this.fb.array([]),
});
this.addRow();
this.addColumn();
}
// Getters for easy access to FormArrays
get gridControls(): FormArray[] {
return (<FormArray>this.myForm.get('grid')).controls as FormArray[];
}
// Getters for easy access to FormArrays
get grid(): FormArray {
return this.myForm.get('grid') as FormArray;
}
getFormArrayControls(input: FormArray): FormControl[] {
return input.controls as FormControl[];
}
// Add a new row to the grid
addRow() {
const newRow = this.fb.array([]);
this.grid.push(newRow);
}
// Add a new column to each row
addColumn() {
this.grid.controls.forEach((row: FormArray) => {
row.push(this.fb.control('', Validators.required));
});
}
// Remove a row from the grid
removeRow(rowIndex: number) {
this.grid.removeAt(rowIndex);
}
// Remove a column from each row
removeColumn(columnIndex: number) {
this.grid.controls.forEach((row: any) => {
row.removeAt(columnIndex);
});
}
}
html
<form [formGroup]="myForm">
<div formArrayName="grid">
<div *ngFor="let row of gridControls; let i = index" [formGroupName]="i">
<div
*ngFor="let cell of getFormArrayControls(row); let j = index"
[formGroupName]="j"
>
<input [formControl]="cell" />
</div>
<button type="button" (click)="removeRow(i)">Remove Row</button>
</div>
</div>
<button type="button" (click)="addRow()">Add Row</button>
<button type="button" (click)="addColumn()">Add Column</button>
</form>
{{ myForm.value | json }}
Upvotes: 1