如何在 ionic 5 中向 ion-select 添加 select all 选项
How to add select all option to ion-select in ionic 5
我尝试添加 ion-select-选项,然后尝试处理 select 更改事件中的所有逻辑,但更改事件根本没有触发。好像不支持事件
<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>
使用 Ionic 多项选择 selects,没有内置的方法来“select 全部”或“select none”,但我想出了一个定制解决方案就是这样做的。您将需要使用自定义 alert component 而不是 <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)。
我同意 Wesley 的观点,因为 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-item 绑定点击事件传递 'selector' 引用。然后你使用 ion-select 的 'open' 方法来访问 'alert' 的实例。
由于警报选项的 'message' 属性 支持“已清理” HTML,您仍然可以将 HTML 元素及其 ID 传递给它(复选框)。然后使用文档参考,您可以获得复选框并添加侦听器(稍后将在 willDismiss 挂钩上删除)。
在 click 方法中你可以实现 select all / none.
的功能
演示:https://stackblitz.com/edit/ionic-angular-v5-2jqnsv?file=src/app/app.component.ts
2021 年 7 月更新: 添加搜索并将 select 全部和搜索移动到自定义元素以便于管理
代码示例:
https://stackblitz.com/edit/ionic-5-angular-10-start-template-6m73vb
以前的方法:
我最终使用@Sergey Rudenko 解决方案并创建了指令,并在更多场景中进行了一些改进和处理 select。有兴趣的朋友请在下面找到相关代码
解决方案 1:Select 所有复选框指令。基于@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:Select 所有按钮都使用指令。基于@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;
}
我尝试添加 ion-select-选项,然后尝试处理 select 更改事件中的所有逻辑,但更改事件根本没有触发。好像不支持事件
<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>
使用 Ionic 多项选择 selects,没有内置的方法来“select 全部”或“select none”,但我想出了一个定制解决方案就是这样做的。您将需要使用自定义 alert component 而不是 <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)。
我同意 Wesley 的观点,因为 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-item 绑定点击事件传递 'selector' 引用。然后你使用 ion-select 的 'open' 方法来访问 'alert' 的实例。 由于警报选项的 'message' 属性 支持“已清理” HTML,您仍然可以将 HTML 元素及其 ID 传递给它(复选框)。然后使用文档参考,您可以获得复选框并添加侦听器(稍后将在 willDismiss 挂钩上删除)。 在 click 方法中你可以实现 select all / none.
的功能演示:https://stackblitz.com/edit/ionic-angular-v5-2jqnsv?file=src/app/app.component.ts
2021 年 7 月更新: 添加搜索并将 select 全部和搜索移动到自定义元素以便于管理
代码示例:
https://stackblitz.com/edit/ionic-5-angular-10-start-template-6m73vb
以前的方法:
我最终使用@Sergey Rudenko 解决方案并创建了指令,并在更多场景中进行了一些改进和处理 select。有兴趣的朋友请在下面找到相关代码
解决方案 1:Select 所有复选框指令。基于@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:Select 所有按钮都使用指令。基于@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;
}