У меня есть стекблиц здесь:
Как это можно изменить, чтобы, если пользователь выберет опцию «все», все флажки становились отмеченными, И текст выбора мата просто говорил «все». Аналогично, если пользователь устанавливает все флажки, кроме опции «все», опция «все» должна стать отмеченной, и, опять же, в тексте опции mat должно быть указано «все».
Спасибо за любую помощь.
Вот решение для вас:
//HTML
<mat-form-field>
<mat-select
#drop
(selectionChange) = "doSomething($event)"
placeholder = "Select numbers"
multiple
[(value)] = "selected"
>
<mat-option
*ngFor = "let num of allNums"
[value] = "num"
(click) = "onClick(num)"
>
{{ num }}
</mat-option>
</mat-select>
</mat-form-field>
//TS
import { Component, ViewChild } from '@angular/core';
import { FormControl } from '@angular/forms';
/**
* @title Mat-Select Multiple initialisation with ngModel
*/
@Component({
selector: 'select-overview-example',
templateUrl: 'select-overview-example.html',
styleUrls: ['select-overview-example.css'],
})
export class SelectOverviewExample {
@ViewChild('drop') dropControl: any;
allNums: string[] = ['all', 'one', 'two', 'three', 'four', 'five'];
selected: string[] = [];
onClick(value: string) {
if (value === 'all') {
if (this.selected.length + 1 === this.allNums.length) {
this.selected = [];
} else {
this.selected = this.allNums;
}
}
}
doSomething(e: any) {
// console.info(e);
}
}
Если вам нужна дополнительная помощь, дайте мне знать.
Я надеюсь, что это покажет всем пользователям самый простой способ: Есть и другие варианты использования, но я думаю, вы поймете идею.
выберите-обзор-example.comComponent.ts
import { Component, OnInit, ViewChild } from '@angular/core';
import { FormControl } from '@angular/forms';
type User = {
id: number;
name: string;
};
@Component({
selector: 'select-overview-example',
templateUrl: 'select-overview-example.html',
styleUrls: ['select-overview-example.css'],
})
export class SelectOverviewExample {
// form
usersCtrl = new FormControl([]);
// public to template
users: User[] = [
{
id: 1,
name: 'stack',
},
{
id: 2,
name: 'over',
},
{
id: 3,
name: 'flow',
},
];
// helper
private isAllSelect = false;
selectedUsers() {
return this.usersCtrl.value.length == this.users.length + 1 // add 1 coz the first option is just a helper
? 'All Users'
: this.usersCtrl.value;
}
selectAllState() {
if (this.isAllSelect) {
this.usersCtrl.patchValue([]);
} else {
this.usersCtrl.patchValue(this.getIds());
}
this.isAllSelect = !this.isAllSelect;
}
selectedOption(id: number) {
// log one id
console.info(id);
/**
* Here you can add the business logic for other use cases:
*
*
* 1- If all selected without fist option, the first option then should be added
* 2- If all options are true but one option de-selected, the first option should de-selected too.
*/
}
submitToServer() {
// dont forget to exclude the first option if all selected
}
private getIds() {
return [...this.users.map((user) => user.id), 0];
}
}
select-overview-example.comComponent.html
<mat-form-field>
<mat-select [formControl] = "usersCtrl" placeholder = "Users" multiple>
<mat-select-trigger *ngIf = "this.usersCtrl.value.length > 0">
{{selectedUsers()}}
</mat-select-trigger>
<mat-option (click) = "selectAllState()" [value] = "0"> {{'All'}} </mat-option>
<mat-option
*ngFor = "let user of users;"
[value] = "user.id"
(click) = "selectedOption(user.id)"
>
{{user.name}}
</mat-option>
</mat-select>
</mat-form-field>
Чтобы избежать ошибок при множественном выборе, значение FormControl
всегда должно иметь массив.
Еще один, который независимо от того, есть ли у вас [(ngModel)] или FormControl
Мы можем получить параметры с помощью ViewChildren, и я выбираю отдельные параметры в массиве и выбираю All.
@ViewChildren(MatOption) options: QueryList<MatOption>;
allNums: string[] = ['one', 'two', 'three', 'four', 'five'];
Наш HTML
<mat-form-field>
<mat-select
#drop
placeholder = "Select numbers"
multiple
>
<mat-select-trigger *ngIf = "drop.value && drop.value.length">
{{drop.value.length>allNums.length?'All':
drop.value[0]===null?drop.value.slice(1):
drop.value}}
</mat-select-trigger>
<mat-option #all (click) = "onClick(all)" [value] = "null">Select all</mat-option>
<mat-option *ngFor = "let num of allNums" [value] = "num" (click) = "onClick()">
{{num}}
</mat-option>
</mat-select>
</mat-form-field>
И функция «onClick»
onClick(el: any = null) {
if (el == this.options.first) {
this.options.forEach((x) => {
x[el.selected ? 'select' : 'deselect']();
});
} else {
const selected = this.options.filter((x, index) => index && x.selected);
if (selected.length == this.allNums.length) this.options.first.select();
if (selected.length == 0) this.options.first.deselect();
}
}
Обновление, предложенное gnisut, мы можем перейти к функции «щелкнуть» параметры (и нам не нужно использовать ViewChild). Я меняю функцию и аргументы для отображения. Таким образом, .html становится похожим
<mat-form-field>
<mat-select [(ngModel)] = "value"
#drop
placeholder = "Select numbers"
multiple
>
<mat-select-trigger *ngIf = "drop.value && drop.value.length">
{{drop.value.length>allNums.length?'All':
drop.value[0]===null?drop.value.slice(1):
drop.value}}
</mat-select-trigger>
<!--see that we pass "drop.options" and "true"-->
<mat-option (click) = "onClick(drop.options,true)" [value] = "null">Select all</mat-option>
<!--see that we pass "drop.options"-->
<mat-option *ngFor = "let num of allNums" [value] = "num" (click) = "onClick(drop.options)">
{{num}}
</mat-option>
</mat-select>
</mat-form-field>
И функция onClick очень «похожа» на предыдущую:
onClick(options:QueryList<MatOption>,isFirst:boolean=false) {
if (isFirst) {
const el=options.first;
options.forEach((x) => {
x[el.selected ? 'select' : 'deselect']();
});
} else {
const selected = options.filter((x, index) => index && x.selected);
if (selected.length == this.allNums.length) options.first.select();
if (selected.length == 0) options.first.deselect();
}
}
@gnitsuk, конечно!. Поскольку у нас есть ссылка на шаблон «#drop» на mat-select, а у matSelect есть свойство: «options» (вы можете увидеть в github вы можете перейти к функции onClick(drop.options)
. Я просто обновляю ответ и stackblitz с вашей идеей.
Отлично, да, я только что попробовал, и все работает нормально. Большое спасибо за ваш ответ и время, а также большое спасибо всем остальным людям, которые ответили, чтобы помочь мне. Я многому научился благодаря вашей помощи.
(Я добавил еще один вопрос): stackoverflow.com/questions/78706735/…
Вот решение вашей проблемы. Я надеюсь, что это позволит выполнить вашу работу с минимальными изменениями. Пожалуйста, дайте мне знать, соответствует ли это вашим требованиям. Спасибо
import { Component } from '@angular/core';
import { MatSelectChange } from '@angular/material';
/** @title Select with multiple selection */
@Component({
selector: 'select-multiple-example',
templateUrl: 'select-multiple-example.html',
styleUrls: ['select-multiple-example.css'],
})
export class SelectMultipleExample {
modules = [
{ value: 'module1', viewValue: 'Module 1' },
{ value: 'module2', viewValue: 'Module 2' },
];
selected: string[] = [];
onSelectionChange(event: MatSelectChange) {
if (event.value.includes('all')) {
event.value = ['all'];
this.selected = ['all'];
}
console.info('Event', event.value, this.selected);
// const allIndex = event.value.indexOf('all');
// if (allIndex > -1 && this.allAlreadySelected == false)
// {
// //if all is selected, select all browsers
// this.selectedModules = ['all', ...this.modules.map(b => b.value)];
// this.allAlreadySelected = !this.allAlreadySelected;
// }
// else if (allIndex > -1 && this.allAlreadySelected) {
// this.selectedModules = [];
// this.allAlreadySelected = !this.allAlreadySelected;
// }
}
}
<mat-form-field>
<mat-select
placeholder = "Select Modules"
multiple
[(ngModel)] = "selected"
(selectionChange) = "onSelectionChange($event)"
>
<mat-option [value] = "'all'">All</mat-option>
<mat-option
*ngFor = "let module of modules"
[value] = "module.value"
[disabled] = "selected.includes('all')"
>{{module.viewValue}}</mat-option
>
</mat-select>
</mat-form-field>
Благодарим вас за вклад в сообщество Stack Overflow. Возможно, это правильный ответ, но было бы очень полезно предоставить дополнительные пояснения к вашему коду, чтобы разработчики могли понять ваши рассуждения. Это особенно полезно для новых разработчиков, которые не так хорошо знакомы с синтаксисом или пытаются понять концепции. Не могли бы вы отредактировать свой ответ, включив в него дополнительную информацию на благо сообщества?
Да, конечно, я только начал отвечать в сообществе, по мере того, как я прогрессирую каждый день, я буду улучшать себя с объяснениями, большое спасибо за предложение.
Большое спасибо за это, очень ценно. Можно ли изменить его так, чтобы функцию onClick можно было сделать «автономной», приняв в качестве дополнительного аргумента переменную, которая в данный момент хранится в this.options? Чтобы не было необходимости иметь параметры @ViewChildren(MatOption): QueryList<MatOption>; в файле ts, поскольку мы будем передавать список объектов MatOption в качестве аргумента функции onClick, когда она вызывается в html-коде.