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
{{myForm.value | json}}and when unselects as well. Also, when setting a model, the checkboxes should be selected accordingly to the user's properties.