Ich bin neu in Angular und Angular Material, jetzt arbeite ich als Unterstützung in einem Projekt. Es gibt ein Raster mit Filtern und ein Kontrollkästchen, um zu überprüfen, ob der Benutzer im Raster aktiv, inaktiv oder nicht ausgewählt ist. Es wäre einfacher mit nur zwei Optionen (aktiv, inaktiv), aber ich muss 3 Zustände dafür machen:
Hier ist ein Checkbox-Beispiel aus der offiziellen Angular Materialdokumentation: https://stackblitz.com/angular/rxdmnbxmkgk?file=app%2Fcheckbox-configurable-example.html
Wie mache ich es am einfachsten?
TL; DR
Hier ist eine fertige Komponente, die die unten dargestellten Lösungen verwendet:
import { Component, forwardRef, OnInit } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { MAT_CHECKBOX_CLICK_ACTION } from '@angular/material';
@Component({
selector: 'app-tri-state-checkbox',
templateUrl: './tri-state-checkbox.component.html',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TriStateCheckboxComponent),
multi: true,
},
{ provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'noop' },
],
})
export class TriStateCheckboxComponent implements ControlValueAccessor {
tape = [null, true, false];
value: boolean;
disabled: boolean;
private onChange: (val: boolean) => void;
private onTouched: () => void;
writeValue(value: boolean) {
this.value = value;
}
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;
}
}
und Vorlage:
<mat-checkbox [ngModel]="value" (click)="next()" [disabled]="disabled" [indeterminate]="value === false" [color]="value === false ? 'warn' : 'accent'">
<ng-content></ng-content>
</mat-checkbox>
Verwendungszweck:
<app-tri-state-checkbox [(ngModel)]="done">is done</app-tri-state-checkbox>
<app-tri-state-checkbox formControlName="done">is done</app-tri-state-checkbox>
Ursprüngliche Antwort
Lösung 1:stackblitz
Die erste Lösung besteht darin, MAT_CHECKBOX_CLICK_ACTION
als noop
bereitzustellen und den ganzen Spaß mit dem Click-Ereignis zu haben. Dies ist jedoch nicht sehr komfortabel, da Sie mehrere Kontrollkästchen auf derselben Seite haben können und nicht alle Kontrollkästchen mit drei Status sind.
Komponente:
import { MAT_CHECKBOX_CLICK_ACTION } from '@angular/material';
@Component({
selector: 'material-app',
templateUrl: 'app.component.html',
providers: [
// provide on THIS component level only
{ provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'noop' }
],
})
export class AppComponent {
tape = [null, true, false];
done = null;
doneControl = new FormControl(false);
}
wo die Werte für das Band (eine Folge von umgeschalteten Werten) sind:
null
für leeres Kontrollkästchentrue
für erledigtfalse
for geht nichtDann verwenden Sie es in der Vorlagendatei:
<mat-checkbox [ngModel]="done"
[indeterminate]="done === false"
(click)="done = tape[(tape.indexOf(done) + 1) % tape.length]"
[color]="done === false ? 'warn' : 'accent'">
Tri-state mat-checkbox with ngModel
</mat-checkbox>
<br>
<mat-checkbox [formControl]="doneControl"
[indeterminate]="doneControl.value === false"
(click)="doneControl.setValue(tape[(tape.indexOf(doneControl.value) + 1) % tape.length])"
[color]="doneControl.value === false ? 'warn' : 'accent'">
Tri-state mat-checkbox with formControl
</mat-checkbox>
Lösung 2:stackblitz
Eine andere Lösung, zu der ich gekommen bin, ist, den ngModelChange
-Handler so zu ändern, dass er auf die vorherigen Werte des Modells reagiert. Dies funktioniert mit ngModel
, jedoch nicht mit formControl
formControlName
. Was ist im Vergleich zur ersten Lösung geändert:
MAT_CHECKBOX_CLICK_ACTION
wird überschriebenngModelChange
geändert.Komponente:
@Component({
selector: 'material-app',
templateUrl: 'app.component.html'
})
export class AppComponent {
tape = [null, true, false];
done = null;
doneControl = new FormControl(false);
}
Vorlage:
<mat-checkbox [ngModel]="done"
[indeterminate]="done === false"
(ngModelChange)="done = tape[(tape.indexOf(done) + 1) % tape.length]"
[color]="done === false ? 'warn' : 'accent'">
Tri-state mat-checkbox with ngModel
</mat-checkbox>
<br>
<mat-checkbox [formControl]="doneControl"
[indeterminate]="doneControl.value === false"
(ngModelChange)="doneControl.setValue(tape[(tape.indexOf(doneControl.value) + 1) % tape.length])"
[color]="doneControl.value === false ? 'warn' : 'accent'">
Tri-state mat-checkbox with formControl
</mat-checkbox>
Hier wird das Modell mit _/einseitiger Bindung festgelegt, der unbestimmte Modus ist streng an den Wert der Variablen false
gebunden und die Farbe wird ebenfalls entsprechend dem Wert geändert.
Wenn Sie ein Arbeitsbeispiel benötigen, können Sie auch das material2 - Projekt hier klonen, und dann
cd material2
npm i
npm run demo-app
Öffnen Sie die Demo-App und navigieren Sie zur Checkbox-Komponente.
Eine Möglichkeit, dies zu tun, besteht darin, MAT_CHECKBOX_CLICK_ACTION auf 'noop' zu setzen. Anschließend müssen Sie die überprüften Werte mit (click) festlegen. Vergessen Sie nicht, sowohl [ngModel] als auch [indeterminate] zu binden.
providers: [
{provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'noop'}
]
Schauen Sie sich dies an: https://github.com/angular/material2/blob/master/src/lib/checkbox/checkbox.md