I am working on a dynamic Form in Angular. There should be an array in another array.
But it has a problem with my form and the following error appears:
[Cannot find control with path: 'gruppen -> 0 -> prueffolge'][1] I have a object structure like this:
"pruefplanTemplate": {
"gruppen": [
"prueffolge": 100,
"name": "test",
"pruefungen": [
"..": "",
"..": ""
]
]
}
This is my code: Component:
import { Component, OnInit } from '@angular/core';
import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-pruefplan-template',
templateUrl: './pruefplan-template.component.html',
styleUrls: ['./pruefplan-template.component.scss']
})
export class PruefplanTemplateComponent implements OnInit {
form = this.fb.group({
gruppen: this.fb.array([
new FormGroup({
pruefungen: this.fb.array([])
})
])
});
constructor(private fb: FormBuilder) { }
ngOnInit(): void {
}
get gruppen() {
return this.form.controls["gruppen"] as FormArray;
}
addPruefplanGruppe() {
const gruppeForm = this.fb.group({
prueffolge: [100, Validators.required],
name: ['', Validators.required],
pruefungen: [[]]
});
this.gruppen.push(gruppeForm);
}
deleteGruppe(gruppenIndex: number) {
this.gruppen.removeAt(gruppenIndex);
}
getPruefung(index: number, control: any): AbstractControl[] {
var pruefungen = control[index].controls;
return pruefungen;
}
addPruefschritt(index: number, gruppe: any) {
var formArray = gruppe.controls['pruefungen'] as FormArray;
const pruefschrittForm = this.fb.group({
beschreibung: ['', Validators.required],
erledigt: [false, Validators.required],
reaktion: ['', Validators.required],
bemerkung: ['', Validators.required]
});
this.getPruefung(index, gruppe).push(pruefschrittForm);
}
}
Template:
<h3>Prüfplan erstellen:</h3>
<p>{{this.gruppen.length}}</p>
<div [formGroup]="form">
<ng-container formArrayName="gruppen">
<ng-container *ngFor="let gruppeForm of gruppen.controls; let i = index">
<div [formGroupName]="i">
<mat-form-field appearance="fill">
<input matInput formControlName="prueffolge" placeholder="Prüffolge">
</mat-form-field>
<mat-form-field appearance="fill">
<input matInput formControlName="name" placeholder="Name">
</mat-form-field>
<mat-icon (click)="deleteGruppe(i)">delete_forever</mat-icon>
<ng-container formArrayName="pruefungen">
<ng-container *ngFor="let pruefschritt of getPruefung(i, gruppeForm); let j = index">
<div [formGroupName]="j">
<mat-form-field appearance="fill">
<input matInput formControlName="beschreibung" placeholder="Beschreibung">
</mat-form-field>
<mat-form-field appearance="fill">
<input matInput formControlName="erledigt" placeholder="Erledigt"> //TODO: Boolean
</mat-form-field>
<mat-form-field appearance="fill">
<input matInput formControlName="reaktion" placeholder="Reaktion">
</mat-form-field>
<mat-form-field appearance="fill">
<input matInput formControlName="bemerkung" placeholder="Bemerkung">
</mat-form-field>
</div>
</ng-container>
</ng-container>
</div>
<button mat-mini-fab (click)="addPruefschritt(i, gruppeForm);">
Prüfschritt
<mat-icon >add</mat-icon>
</button>
</ng-container>
</ng-container>
<button mat-mini-fab (click)="addPruefplanGruppe();">
Gruppe
<mat-icon >add</mat-icon>
</button>
</div>
Model:
export interface PruefplanTemplate {
gruppen: Gruppe[];
}
export interface Gruppe {
prueffolge: number;
name: string;
pruefungen: Pruefung[];
}
export interface Pruefung {
beschreibung: string;
erledigt: boolean;
reaktion: string;
bemerkung: string;
}
I hope someone has more experience with FormArray than me!
Thank you guys! [1]: https://i.stack.imgur.com/hEAGL.png
CodePudding user response:
When we use a FormArray, always use a "getter" to get the formArray. If we has a formArray of FormArray, we cannot use a "getter" else a function with an index
So you has
get gruppen()
{
return this.form.get("gruppen") as FormArray;
}
getPruefungen(index:number)
{
return this.gruppen.at(index).get('pruefungen') as FromArray
}
Now is "as always"
<form [formGroup]="form">
<div formArrayName="gruppen">
<div *ngFor="let group of gruppen.controls;let i=index" [formGroupName]="i">
<input formControlName="prueffolge">
....
<!--see that it's the same constructor for the inner
but use getPruefungen(i) -->
<div formArrayName="pruefungen">
<div *ngFor="let group of getPruefungen(i).controls;let j=index"
[formGroupName]="j">
<input formControlName="beschreibung">
....
</div>
</div>
</div>
</div>
</form>
CodePudding user response:
The problem is that you need to define your pruefungen
as a FormArray
not ForControl
, like this:
addPruefplanGruppe() {
const gruppeForm = this.fb.group({
prueffolge: [100, Validators.required],
name: ['', Validators.required],
pruefungen: this.fb.array([]). // <---- see this line
});
this.gruppen.push(gruppeForm);
}