Reputation: 3082
I'm learning reactive forms still, and I want to have multiple checkboxes for a property that is array (e.g. hobby). So I defined the group as follows
this.myForm = this.fb.group({
name: ['', Validators.required],
hobbies: this.fb.array([])
});
Hobbies is an array: hobbies = ['Cooking', 'Swimming', 'Hiking', 'Dancing'];
Now, in HTML, I defined the checkboxes as follows:
<div>
<span *ngFor="let hobby of hobbies">
<label>
<input type="checkbox" [value]="hobby" (click)="addToHobby(hobby)"> {{hobby}}
</label>
<br />
</span>
</div>
Now when checking an element it doesn't add it to the hobbies property at all, it just duplicates the actual HTML element. What am I doing wrong?
Here's the code: https://plnkr.co/edit/j8V189VoWKvloNgwOr7p?p=preview
Upvotes: 4
Views: 3898
Reputation: 3082
OK I managed to get something working. The link is available below, but firstly, here's my chain of thought.
Firstly, we need to just define an array of all values, possibly we get this from a web service, but still, I mock them like this:
hobbies = [new Hobby(1, 'Cooking'), new Hobby(2, 'Swimming'), new Hobby(3, 'Hiking'), new Hobby(4, 'Dancing')];
I purposely added id as well, so it will mimic the real world more accurately. Now, we need to define the form. Since the multi checkboxes is not going to work, I decided to represent an array of individual checkboxes, each having several attributes, but at least two are necessary: the boolean to decide if that checkbox in array was selected and a name so we can know what we're selecting.
In order to achieve this, we need to firstly create an array that would fit the form, which is done as follows:
let hobbiesArray = [];
for (let hobby of this.hobbies) {
hobbiesArray.push(this.fb.group({
isChosen: false,
name: hobby.hobbyName,
id: hobby.id
}));
}
As evident, I created new fb.group
for each hobby and they're all placed in an array. This array is then used to create the form, as follows:
this.myForm = this.fb.group({
hobbiesList: this.fb.array(hobbiesArray)
});
Now we have an fb.array
of fb.groups
. Now, when it comes to HTML, I have several concerns.
The logic is "go through the myForm.hobbiesList
and manipulate isChosen
while keeping the name
readonly - sort of. Here's the code.
<div formArrayName="hobbiesList">
<div *ngFor="let hobby of hobbiesList.controls; let i=index" [formGroupName]="i" >
<input type="checkbox" formControlName="isChosen" /> {{hobby.controls.name.value}}
</div>
</div>
Here's my concern: can I just address the name like this: {{hobby.controls.name.value}}
? What harm can this do? Am I breaking any Angular2/4 rules?
OK, so, when confirming the selected hobbies, we get the actual array with name and ids (without the isChosen
values) as follows:
submitMe(): void {
let items = this.myForm.value;
this.mySelectedHobbies = items.hobbiesList.filter(x => x.isChosen).map(x => { return { name: x.name, id: x.id }; });
}
So yeah, this is my design. I'm not sure if it's all allowed what I did but I find this the easiest way to solve the issue. What do you guys think?
Here's the code: https://plnkr.co/edit/8OKiQMK788R2uCt2OWzm?p=preview
Upvotes: 4