Je suis nouveau sur Angular et Angular, je travaille maintenant comme support dans certains projets. Il y a une grille avec des filtres et une case à cocher, qui vérifie si l'utilisateur dans la grille est actif, inactif ou non choisi. Ce serait plus simple avec seulement deux options (actif, inactif) mais bon, je dois faire 3 états pour cela:
Voici un exemple de case à cocher officiel Angular Documentation: https://stackblitz.com/angular/rxdmnbxmkgk?file=app%2Fcheckbox-configurable-example.html
Comment le faire de la manière la plus simple?
TL; DR
Voici un composant prêt qui utilise les solutions présentées ci-dessous:
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;
}
}
et modèle:
<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>
Réponse originale
Solution 1:stackblitz
La première solution consiste à fournir MAT_CHECKBOX_CLICK_ACTION
en tant que noop
et à vous amuser avec l'événement click, mais ce n'est pas très pratique, car vous pouvez avoir plusieurs cases à cocher sur la même page et toutes ne sont pas des cases à trois états.
Composant:
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);
}
où les valeurs de la bande (une séquence de valeurs basculées) sont:
null
pour case à cocher videtrue
pour faitfalse
pour ne fera pasEnsuite, utilisez-le dans le fichier modèle:
<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>
Solution 2:stackblitz
Une autre solution à laquelle je suis arrivé est de changer le gestionnaire ngModelChange
pour réagir aux valeurs précédentes du modèle. Cela fonctionne avec ngModel
mais ne fonctionne pas avec formControl
formControlName
. Qu'est-ce qui a changé par rapport à la première solution:
MAT_CHECKBOX_CLICK_ACTION
est écraséngModelChange
Composant:
@Component({
selector: 'material-app',
templateUrl: 'app.component.html'
})
export class AppComponent {
tape = [null, true, false];
done = null;
doneControl = new FormControl(false);
}
Modèle:
<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>
Ici, le modèle est défini avec _/one-way binding, le mode indéterminé est strictement lié à la valeur false
et la couleur est également modifiée en fonction de la valeur.
Si vous avez besoin d'un exemple de travail, vous pouvez également cloner le projet material2 project here , puis:
cd material2
npm i
npm run demo-app
Ouvrez l'application de démonstration et accédez au composant case à cocher.
Une façon de faire est de définir MAT_CHECKBOX_CLICK_ACTION sur 'noop' et vous devrez ensuite définir les valeurs cochées avec (clic). N'oubliez pas de lier à la fois [ngModel] et [indéterminé].
providers: [
{provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'noop'}
]
Regardez ceci: https://github.com/angular/material2/blob/master/src/lib/checkbox/checkbox.md