The problem with the @AJT_82 answer is that if you want to modify the model using form.reset() or or form.patchValue(), it won't work. To resolve these problems you need to implement ControlValueAccessor interface.
Basically you need to create 2 components: group component which holds the model value and implements ControlValueAccessor and checkbox component, the actual checkbox.
I have written a blog post with detailed explanation as well as created a plunker which demonstrate some examples.
Final usage:
<checkbox-group [(ngModel)]="selectedItems">
<checkbox value="item1">Item 1</checkbox>
<checkbox value="item2">Item 2</checkbox>
<checkbox value="item3">Item 3</checkbox>
<checkbox value="item4">Item 4</checkbox>
</checkbox-group>
Implementation of group component:
@Component({
selector: 'checkbox-group',
template: `<ng-content></ng-content>`,
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CheckboxGroupComponent),
multi: true
}]
})
export class CheckboxGroupComponent implements ControlValueAccessor {
private _model: any;
// here goes implementation of ControlValueAccessor
...
addOrRemove(value: any) {
if (this.contains(value)) {
this.remove(value);
} else {
this.add(value);
}
}
contains(value: any): boolean {
if (this._model instanceof Array) {
return this._model.indexOf(value) > -1;
} else if (!!this._model) {
return this._model === value;
}
return false;
}
// implementation for add and remove
...
}
Checkbox component:
@Component({
selector: 'checkbox',
template: `
<div (click)="toggleCheck()">
<input type="checkbox" [checked]="isChecked()" />
<ng-content></ng-content>
</div>`
})
export class CheckboxComponent {
@Input() value: any;
constructor(@Host() private checkboxGroup: CheckboxGroupComponent) {
}
toggleCheck() {
this.checkboxGroup.addOrRemove(this.value);
}
isChecked() {
return this.checkboxGroup.contains(this.value);
}
}
Child checkbox controls have reference to group component (@Host() decorator). When a checkbox is clicked toggleCheck() call addOrRemove() method on group component and if checkbox's value is already in the model, it is removed, otherwise it is added to the model.