typescript - Tabulka Angular Material s výběrem - hlavní přepínač by měl nejprve zrušit výběr
Upravil jsem (masterToggle) původní příklad Angular Material Table - Stackblitz tak, aby po vybrání některých řádků hlavní přepínač všechny odznačil (místo označení všech - podobně jako v Gmailu).
Funguje to, ale hlavní přepínací zaškrtávací políčko v záhlaví nefunguje podle očekávání - po jeho kliknutí pro zrušení výběru - logika zruší výběr vybraných řádků, ale hlavní přepínací zaškrtávací políčko neodráží hodnotu modelu:
[checked]="selection.hasValue() && isAllSelected()"Očekával bych, že hlavní přepínací zaškrtávací políčko nebude zaškrtnuté, pokud výraz vyhodnotí na nepravdu (viz obrázek níže).
Myslím, že to má něco společného s animacemi.
Zde je upravený příklad: Stackblitz
masterToggle() {
// if there is a selection then clear that selection
if (this.isSomeSelected()) {
this.selection.clear();
} else {
this.isAllSelected() ?
this.selection.clear() :
this.dataSource.data.forEach(row => this.selection.select(row));
}
}
Odpověď č. 1
Aktuálně neaktualizujete this.selection.selected.length při klikání na zaškrtávací políčko, takže se délka neaktualizuje správně.
Musíte explicitně změnit stav mat-checkbox, jinak se bude stále přepínat samo, takže jsem použil šablonovou referenci na mat-checkbox, aby bylo odškrtnuto.
Metoda isSomeSelected() se nespouští při kliknutí na mat-cell. Aby bylo možné správně zkontrolovat podmínku masterToggle(), je potřeba tuto metodu vyvolat při kliknutí na mat-checkbox. Zkontrolujte mé řešení, tuto funkci jsem přidal do události change, aby fungovala správně.
<td mat-cell *matCellDef="let row" >
<mat-checkbox (click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null;isSomeSelected()"
[checked]="selection.isSelected(row)">
</mat-checkbox>
</td>
Upravil jsem váš kód, zkontrolujte to zde: https://stackblitz.com/edit/angular-rmqg54-7rjmaj
Odpověď č. 2
Narazil jsem na stejný problém, moje řešení bylo změnit stav checked hlavního přepínače tak, aby byl pravdivý, když je vybrána jakákoliv položka, místo jen když jsou vybrány všechny položky (StackBlitz)
<th mat-header-cell *matHeaderCellDef>
<mat-checkbox (change)="$event ? masterToggle() : null"
[checked]="selection.hasValue()"
[indeterminate]="selection.hasValue() && !isAllSelected()">
</mat-checkbox>
</th>
Když je vybrána vlastní podmnožina položek, indeterminate bude pravda, takže zaškrtnutí se ve skutečnosti nezobrazuje. Jak však zmínil @Chellappan, zaškrtávací políčko přepíná stav zaškrtnutí při každém kliknutí (viz zdroj), takže při dalším kliknutí se zaškrtávací políčko přepne do nezaškrtnutého stavu, jak je požadováno.
/**
* Event handler for checkbox input element.
* Toggles checked state if element is not disabled.
* Do not toggle on (change) event since IE doesn't fire change event when
* indeterminate checkbox is clicked.
* @param event
*/
_onInputClick(event: Event) {
[...]
this._transitionCheckState(
this._checked ? TransitionCheckState.Checked : TransitionCheckState.Unchecked);
[...]
}
Bohužel toto spojuje kód s tím, co lze sporně považovat za implementační detail. Dalším možným řešením je vrátit false z obsluhy kliknutí zaškrtávacího políčka, aby se zabránilo vyhodnocení Angular obsluhy kliknutí, avšak při mém testování interakce pomocí klávesnice na zaškrtávacím políčku nezpůsobuje vyvolání obsluhy kliknutí zaškrtávacího políčka, ale spouští Angular obsluhu, takže chyba přetrvá.
Pravdivé, ale složité řešení by bylo nastavit MAT_CHECKBOX_CLICK_ACTION na noop a implementovat vlastní akci při kliknutí
