I want to define a question which has some answers. Here is my code:
formGroup!:FormGroup;
answerFormGroup:FormGroup=this.formBuilder.group({
text: ['d', Validators.required],
value: [0, Validators.required]
});
ngOnInit() {
this.formGroup = this.formBuilder.group({
question:['',Validators.required],
questionType: [1,Validators.required],
answers: new FormArray([])
});
this.questionTypes=this.localDataService.questionType;
this.addAnswer();
}
// convenience getters for easy access to form fields
get answers() {
return this.formGroup.controls["answers"] as FormArray;
}
addAnswer(){
this.answers.push(this.formBuilder.group({
text: ['d', Validators.required],
value: [0]
}));
}
submit(){
console.log(JSON.stringify(this.formGroup.value));
}
But when I submit my form the answer values are the default values and it does not change. In the form I changed the default value "d" to "b", and it is still "d". Here is the result:
{
"question": "question1",
"questionType": 1,
"answers": [
{
"text": "d",
"value": 0
}
]
}
Here is the template:
<form class="question-card" [formGroup]="formGroup">
<mat-form-field>
<mat-label>Question</mat-label>
<input matInput formControlName="question" placeholder="Question">
</mat-form-field>
<mat-form-field>
<mat-label>Type</mat-label>
<mat-select formControlName="questionTypeControl" (selectionChange)="updateQuestionType($event)">
@for (item of questionTypes; track item) {
<mat-option [value]="item.id">
<mat-icon>{{item.icon}}</mat-icon> {{item.text}}
</mat-option>
}
</mat-select>
</mat-form-field>
<div [formGroup]="answerFormGroup">
@for(item of answers.controls; track item){
<mat-form-field>
<mat-label>Value</mat-label>
<input matInput type="text" formControlName="value">
</mat-form-field>
<mat-icon class="delete-btn" (click)="deleteAnswer($event)">delete_forever</mat-icon>
<mat-form-field>
<mat-label>Text</mat-label>
<input matInput type="text" formControlName="text">
</mat-form-field>
}
</div>
<button mat-mini-fab (click)="addAnswer()">
<mat-icon>add</mat-icon>
</button>
<button type="button" (click)="submit()">Submit</button>
</form>
You are updating the text
control in the answerFormGroup
FormGroup but not formGroup
. From here:
<div [formGroup]="answerFormGroup">
...
</div>
In the formGroup
template, you need to have the formArray
control for the answers
.
<form class="question-card" [formGroup]="formGroup">
...
<ng-container formArrayName="answers">
@for (item of answers.controls; track item; let i = $index) {
<div [formGroupName]="i">
<mat-form-field>
<mat-label>Value</mat-label>
<input matInput type="text" formControlName="value" />
</mat-form-field>
<mat-icon class="delete-btn" (click)="deleteAnswer($event)"
>delete_forever</mat-icon
>
<mat-form-field>
<mat-label>Text</mat-label>
<input matInput type="text" formControlName="text" />
</mat-form-field>
</div>
}
</ng-container>
...
</form>
The @for
syntax is a new feature in Angular 17 and quite new to me. If you are looking for the old way:
<ng-container formArrayName="answers">
<ng-container *ngFor="let answer of answers.controls; let i = index">
<div [formGroupName]="i">
<mat-form-field>
<mat-label>Value</mat-label>
<input matInput type="text" formControlName="value" />
</mat-form-field>
<mat-icon class="delete-btn" (click)="deleteAnswer($event)"
>delete_forever</mat-icon
>
<mat-form-field>
<mat-label>Text</mat-label>
<input matInput type="text" formControlName="text" />
</mat-form-field>
</div>
</ng-container>
</ng-container>
Note that you are missing questionTypeControl
control in the formGroup
.