Angular 5, Angular Material Checkbox with 3 states (checked, unchecked, indeterminate)
@angular/material >= 9
Here is a ready-to-use component:
import { Component, forwardRef, Input } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { MatCheckboxDefaultOptions, MAT_CHECKBOX_DEFAULT_OPTIONS } from '@angular/material/checkbox';
@Component({
selector: 'app-tri-state-checkbox',
templateUrl: './tri-state-checkbox.component.html',
styleUrls: ['./tri-state-checkbox.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TriStateCheckboxComponent),
multi: true,
},
{ provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: { clickAction: 'noop' } as MatCheckboxDefaultOptions },
],
})
export class TriStateCheckboxComponent implements ControlValueAccessor {
@Input() tape = [null, true, false];
value: any;
disabled: boolean;
private onChange: (val: boolean) => void;
private onTouched: () => void;
writeValue(value: any) {
this.value = value || this.tape[0];
}
setDisabledState(disabled: boolean) {
this.disabled = disabled;
}
next() {
this.onChange(this.value = this.tape[(this.tape.indexOf(this.value) + 1) % this.tape.length]);
this.onTouched();
}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: any) {
this.onTouched = fn;
}
}
and template:
<mat-checkbox [ngModel]="value" (click)="next()" [disabled]="disabled" [indeterminate]="value === false" [color]="value === false ? 'warn' : 'accent'">
<ng-content></ng-content>
</mat-checkbox>
Usage:
<app-tri-state-checkbox [(ngModel)]="done">is done</app-tri-state-checkbox>
<app-tri-state-checkbox formControlName="done">is done</app-tri-state-checkbox>
You can also override default tape to e.g. enum values:
<app-tri-state-checkbox [tape]="customTape" [(ngModel)]="done">is done</app-tri-state-checkbox>
where customTape
replaces default values [null, true, false]
customTape = [Status.open, Status.complete, Status.cancelled];
@angular/material <= 8
Just change
{ provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: { clickAction: 'noop' } as MatCheckboxDefaultOptions },
to the deprecated since version 9 MAT_CHECKBOX_CLICK_ACTION
{ provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'noop' },