I'm trying to loop over a FormGroup of FormControls in the template. I want to display a checkbox for each. This is how my component.ts looks like
tags = ["vegan","vegetarian","meat","fruit","vegetable","seafood","fish","nut"];
get tagsForForm() {
return this.foodForm.get('tags') as FormGroup;
}
createTagsForForm(): {[key: string]: any} {
let tagsForForm = {};
for (let i = 0; i < this.tags.length; i++){
tagsForForm[this.tags[i]]=false;
}
return tagsForForm;
}
ngOnInit(){
this.foodForm = this.fb.group({
foodName: [''],
tags: this.fb.group(this.createTagsForForm())
});
}
My template.html looks like this:
<section formGroupName="tags">
<h2>Tags</h2>
<input *ngFor="let tag of tagsForForm" [formControlName]="tag" type="checkbox">
</section>
In the console I'm getting this error:
"Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays."
Is it not possible to loop over a FormGroup in the template or is only something missing?
You need to use keyvalue
pipe to loop over objects. Try the following
<input *ngFor="let tag of tagsForForm | keyvalue" [formControlName]="tag.value" type="checkbox">
The value of the property is available in tag.value
and the key of the property is available in tag.key
.
Update
It appears this.foodForm.get('tags') as FormGroup
doesn't return the correct object to loop over. You could try to replace it with this.foodForm.controls['tags']['controls'];
. Try the following
Controller
export class AppComponent {
foodForm: FormGroup;
tags = ["vegan", "vegetarian", "meat", "fruit", "vegetable", "seafood", "fish","nut"];
get tagsForForm() {
return this.foodForm.controls['tags']['controls'];
}
constructor(private fb: FormBuilder) {}
createTagsForForm(): {[key: string]: any} {
let tagsForForm = {};
for (let i = 0; i < this.tags.length; i++){
tagsForForm[this.tags[i]] = false;
}
return tagsForForm;
}
ngOnInit() {
this.foodForm = this.fb.group({
foodName: [''],
tags: this.fb.group(this.createTagsForForm())
});
}
}
Template
<form [formGroup]="foodForm">
<label>Name: </label>
<input formControlName="foodName" />
<section [formGroup]="foodForm.controls.tags">
<ng-container *ngFor="let tag of tagsForForm | keyvalue">
<label>{{ tag.key | titlecase }}</label>
<input [formControlName]="tag.key" type="checkbox">
<br>
</ng-container>
</section>
</form>
Alternatively if you're generating the nested form group using a member variable (tags
here), you could loop over it to avoid the getter and some additional overhead. The following would also work
<form [formGroup]="foodForm">
<label>Name: </label>
<input formControlName="foodName" />
<section [formGroup]="foodForm.controls.tags">
<ng-container *ngFor="let tag of tags">
<label>{{ tag | titlecase }}</label>
<input [formControlName]="tag" type="checkbox">
<br>
</ng-container>
</section>
</form>
Working example: Stackblitz