#angular #ionic-framework #ionic5
#angular #ionic-framework #ionic5
Вопрос:
Я попытался добавить опцию выбора ion, а затем попытался обработать логику выбора всех в событии изменения, но событие изменения вообще не срабатывает. кажется, он не поддерживает события
<ion-item>
<ion-label>Test</ion-label>
<ion-select [(ngModel)]="selectedValues" multiple="true">
<ion-select-option (ionChange)="selectAll()">Select All</ion-select-option>
<ion-select-option [value]="option" *ngFor="let option of items">{{option}}
</ion-select-option>
</ion-select>
</ion-item>
Ответ №1:
В Ionic с несколькими вариантами выбора нет встроенного способа «выбрать все» или «выбрать ни одного», но я придумал пользовательское решение, которое делает именно это. Вам нужно будет использовать пользовательский компонент оповещения вместо an <ion-select>
, и вам нужно будет вызвать оповещение программно.
constructor(
private alertController: AlertController,
public platform: Platform
) {}
async showAlert() {
let buttons = [
{
text: 'All',
cssClass: 'all-none-button',
handler: () => {
// check all checkboxes
alert.inputs = alert.inputs.map((checkbox) => {
checkbox.checked = true;
return checkbox;
});
return false;
}
}, {
text: 'None',
cssClass: 'all-none-button',
handler: () => {
// uncheck all checkboxes
alert.inputs = alert.inputs.map((checkbox) => {
checkbox.checked = false;
return checkbox;
});
return false;
}
}, {
text: 'OK',
handler: (data) => {
// handle the data returned from the alert here
console.log(data);
}
}, {
text: 'Cancel',
role: 'cancel',
}
];
// adjust button order in four button layout for ios
if (this.platform.is('ios')) {
const okButton = { ...buttons[2] };
const cancelButton = { ...buttons[3] };
buttons = [buttons[0], buttons[1], cancelButton, okButton];
}
const alert = await this.alertController.create({
header: 'Select Option',
inputs: [
{
label: 'Option 1',
type: 'checkbox',
value: 'one',
checked: false
},
{
label: 'Option 2',
type: 'checkbox',
value: 'two',
checked: false
},
{
label: 'Option 3',
type: 'checkbox',
value: 'three',
checked: false
},
],
cssClass: 'four-button-alert',
buttons: [...buttons]
});
await alert.present();
}
И вам также понадобится немного пользовательского CSS, чтобы получить макет из четырех кнопок для этого пользовательского оповещения.
.four-button-alert.md {
.alert-button-group-vertical {
display: block;
button:nth-of-type(1),
button:nth-of-type(2) {
float: left;
color: var(--ion-color-medium);
}
button:nth-of-type(3),
button:nth-of-type(4) {
float: right;
}
}
}
.four-button-alert.ios {
.alert-button-group-vertical {
flex-direction: row !important;
button:nth-of-type(1) {
color: var(--ion-color-medium);
}
button:nth-of-type(2) {
color: var(--ion-color-medium);
border-right: none;
}
}
}
Готовый продукт выглядит следующим образом (iOS и Android).
Ответ №2:
Я согласен с Уэсли в том, что, поскольку ion-select использует контроллер оповещений или всплывающее окно под капотом, лучшим способом может быть использование пользовательского оповещения. Но если вам нужно сохранить «внешний вид» ion-select, вы можете сделать следующее:
HTML:
<ion-item (click)="openSelector(selector)">
<ion-label>Pizza Toppings</ion-label>
<ion-select #selector style="pointer-events: none" [interfaceOptions]="customAlertOptions" multiple="true" [value]="basket">
<ion-select-option *ngFor="let option of options" [value]="option">{{option}}</ion-select-option>
</ion-select>
</ion-item>
TS:
import { Inject, Component, Renderer2 } from '@angular/core';
import { DOCUMENT } from '@angular/common';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
options = ["cheese", "pepperoni", "basil"];
basket = [];
listener;
selectAllCheckBox: any;
checkBoxes: HTMLCollection;
customAlertOptions: any = {
header: 'Pizza Toppings',
subHeader: 'Select All:',
message: '<ion-checkbox id="selectAllCheckBox"></ion-checkbox>'
};
constructor(@Inject(DOCUMENT) private document: Document, private renderer: Renderer2) {}
openSelector(selector) {
selector.open().then((alert)=>{
this.selectAllCheckBox = this.document.getElementById("selectAllCheckBox");
this.checkBoxes = this.document.getElementsByClassName("alert-checkbox");
this.listener = this.renderer.listen(this.selectAllCheckBox, 'click', () => {
if (this.selectAllCheckBox.checked) {
for (let checkbox of this.checkBoxes) {
if (checkbox.getAttribute("aria-checked")==="false") {
(checkbox as HTMLButtonElement).click();
};
};
} else {
for (let checkbox of this.checkBoxes) {
if (checkbox.getAttribute("aria-checked")==="true") {
(checkbox as HTMLButtonElement).click();
};
};
}
});
alert.onWillDismiss().then(()=>{
this.listener();
});
})
}
}
По сути, вы отключаете обработчик щелчков по умолчанию в ion-select и передаете ссылку «селектор» через событие щелчка, связанное с ion-элементом. Затем вы используете метод ‘open’ ion-select, чтобы получить доступ к экземпляру ‘alert’.
Поскольку свойство ‘message’ параметров оповещения поддерживает «очищенный» HTML, вы все равно можете передать ему HTML-элемент (флажок) с его идентификатором. Затем, используя ссылку на документ, вы устанавливаете флажок и добавляете прослушиватель (позже он будет удален на крючке willDismiss).
Внутри метода click вы можете реализовать функциональность выбора all / none.
Демо-версия: https://stackblitz.com/edit/ionic-angular-v5-2jqnsv?file=src/app/app.component.ts
Комментарии:
1. Спасибо, это решило мою проблему, но я хочу снять флажок selectAll, когда какой-либо из элементов не отмечен. Любой намек на это
Ответ №3:
Обновление июль-2021: добавлен поиск и перенесен выбор всех и поиск в пользовательские элементы для удобства управления
Пример кода :
https://stackblitz.com/edit/ionic-5-angular-10-start-template-6m73vb
Предыдущий подход:
В итоге я использовал решение @Sergey Rudenko и создал директиву с некоторыми дополнительными улучшениями и обработкой select all в большем количестве сценариев. Если кто-либо заинтересован, пожалуйста, найдите соответствующий код ниже
Решение 1: Выберите директиву All Checkbox. На основе ответа @Sergey Rudenko
import { ContentChild, Directive, HostListener, Renderer2 } from '@angular/core';
import { IonSelect } from '@ionic/angular';
@Directive({
selector: '[selectAllDirective]'
})
export class SelectAllDirective {
@ContentChild(IonSelect) ionSelect;
constructor(private renderer: Renderer2) { }
ngAfterViewInit() {
this.ionSelect.el.style.pointerEvents = "none";
}
@HostListener('click', ['$event'])
onClick() {
this.ionSelect.open().then(alert => {
let id = "selectAllCheckBox";
alert.message = `<ion-checkbox id="${id}"></ion-checkbox><ion-label class="m-l-15">Select All</ion-label>`;
setTimeout(() => {
let selectAll: any = alert.querySelector("#" id);
let checkboxes = Array.from(alert.querySelectorAll(".alert-checkbox"));
let setState = () => {
let isAllChecked = checkboxes.every((c: any) => c.ariaChecked === "true");
let isAllUnChecked = checkboxes.every((c: any) => c.ariaChecked === "false");
if (isAllChecked || isAllUnChecked) {
selectAll.indeterminate = false;
selectAll.checked = isAllChecked;
} else {
selectAll.indeterminate = true;
}
}
setState();
let checkboxListeners = checkboxes.map(ci => this.renderer.listen(ci, 'click', () => {
setTimeout(setState);
}));
let selectAllListener = this.renderer.listen(selectAll, 'click', (event) => {
setTimeout(() => alert.inputs = alert.inputs.map(i => { i.checked = event.target.checked; return i; }));
});
alert.onWillDismiss().then(() => {
selectAllListener();
checkboxListeners.forEach(i => i());
});
});
});
}
}
Решение 2: выберите все с помощью кнопок, используя директиву. На основе ответа @Wesley
import { ContentChild, Directive, HostListener, Renderer2 } from '@angular/core';
import { IonSelect } from '@ionic/angular';
@Directive({
selector: '[selectAllWithButtonDirective]'
})
export class SelectAllWithButtonDirective {
@ContentChild(IonSelect) ionSelect;
constructor(private renderer: Renderer2) { }
ngAfterViewInit() {
this.ionSelect.el.style.pointerEvents = "none";
}
@HostListener('click', ['$event'])
onClick() {
this.ionSelect.open().then(alert => {
alert.cssClass = 'unset-vertical-buttons';
alert.buttons = [{
text: 'All',
handler: () => {
alert.inputs = alert.inputs.map((checkbox) => {
checkbox.checked = true;
return checkbox;
});
return false;
}
}, {
text: 'None',
handler: () => {
alert.inputs = alert.inputs.map((checkbox) => {
checkbox.checked = false;
return checkbox;
});
return false;
}
}, ...alert.buttons,];
});
}
}
styles.css
.unset-vertical-buttons .alert-button-group-vertical {
flex-direction: row !important;
}
.m-l-15 {
margin-left: 15px;
}
пример кода обеих директив: https://stackblitz.com/edit/ionic-5-angular-10-start-template-hu3y3u?file=src/app/tabs/select-all-with-button-directive.ts