it-swarm.com.de

Angular 5 Angular Material Checkbox mit 3 Zuständen (markiert, nicht markiert, unbestimmt)

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:

  1. 1. Klick - Aktiviert
  2. 2. Klick - Nicht markiert für inaktiv
  3. 3. Klick - Unbestimmt für nicht ausgewählt

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?

6
TomasThall

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ästchen
  • true für erledigt
  • false for geht nicht

Dann 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 formControlformControlName. Was ist im Vergleich zur ersten Lösung geändert:

  • kein MAT_CHECKBOX_CLICK_ACTION wird überschrieben
  • klickereignis wird in ngModelChange 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.

6
smnbbrv

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. 

0
Liviu Ilea

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

0
rcunha