feat(alert): accept Promise for button handler (#25702)

Resolves #25700

Co-authored-by: Sean Perkins <sean@ionic.io>
This commit is contained in:
Hans Krywalsky
2022-08-03 17:33:37 +02:00
committed by GitHub
parent 11c69c8df5
commit 8e4783c172
4 changed files with 68 additions and 9 deletions

View File

@ -53,10 +53,12 @@ export type AlertTextareaAttributes = { [key: string]: any };
*/
export type AlertInputAttributes = { [key: string]: any };
type AlertButtonOverlayHandler = boolean | void | { [key: string]: any };
export interface AlertButton {
text: string;
role?: 'cancel' | 'destructive' | string;
cssClass?: string | string[];
id?: string;
handler?: (value: any) => boolean | void | { [key: string]: any };
handler?: (value: any) => AlertButtonOverlayHandler | Promise<AlertButtonOverlayHandler>;
}

View File

@ -335,24 +335,24 @@ export class Alert implements ComponentInterface, OverlayInterface {
forceUpdate(this);
}
private buttonClick(button: AlertButton) {
private async buttonClick(button: AlertButton) {
const role = button.role;
const values = this.getValues();
if (isCancel(role)) {
return this.dismiss({ values }, role);
}
const returnData = this.callButtonHandler(button, values);
const returnData = await this.callButtonHandler(button, values);
if (returnData !== false) {
return this.dismiss({ values, ...returnData }, button.role);
}
return Promise.resolve(false);
return false;
}
private callButtonHandler(button: AlertButton | undefined, data?: any) {
private async callButtonHandler(button: AlertButton | undefined, data?: any) {
if (button?.handler) {
// a handler has been provided, execute it
// pass the handler the values from the inputs
const returnData = safeCall(button.handler, data);
const returnData = await safeCall(button.handler, data);
if (returnData === false) {
// if the return value of the handler is false then do not dismiss
return false;

View File

@ -0,0 +1,28 @@
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('alert: basic', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/src/components/alert/test/basic');
});
test('should dismiss when async handler resolves', async ({ page }) => {
const ionAlertDidPresent = await page.spyOnEvent('ionAlertDidPresent');
const ionAlertDidDismiss = await page.spyOnEvent('ionAlertDidDismiss');
const ionLoadingDidDismiss = await page.spyOnEvent('ionLoadingDidDismiss');
const alert = page.locator('ion-alert');
await page.click('#asyncHandler');
await ionAlertDidPresent.next();
await page.click('.alert-button');
await expect(alert).toBeVisible();
await ionLoadingDidDismiss.next();
await ionAlertDidDismiss.next();
await expect(alert).toBeHidden();
});
});

View File

@ -14,8 +14,9 @@
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
</head>
<script type="module">
import { alertController } from '../../../../dist/ionic/index.esm.js';
import { alertController, loadingController } from '../../../../dist/ionic/index.esm.js';
window.alertController = alertController;
window.loadingController = loadingController;
</script>
<body>
@ -30,9 +31,12 @@
<ion-button id="basic" expand="block" onclick="presentAlert()">Alert</ion-button>
<ion-button id="longMessage" expand="block" onclick="presentAlertLongMessage()">Alert Long Message</ion-button>
<ion-button id="multipleButtons" expand="block" onclick="presentAlertMultipleButtons()"
>Multiple Buttons (>2)</ion-button
>
>Multiple Buttons (>2)
</ion-button>
<ion-button id="noMessage" expand="block" onclick="presentAlertNoMessage()">Alert No Message</ion-button>
<ion-button id="asyncHandler" expand="block" onclick="presentAlertAsyncHandler()"
>Alert Async Handler</ion-button
>
<ion-button id="confirm" expand="block" onclick="presentAlertConfirm()">Confirm</ion-button>
<ion-button id="prompt" expand="block" onclick="presentAlertPrompt()">Prompt</ion-button>
<ion-button id="radio" expand="block" onclick="presentAlertRadio()">Radio</ion-button>
@ -46,6 +50,7 @@
--min-width: 0;
--max-width: 200px;
}
#delete-button {
color: #eb445a;
}
@ -351,6 +356,30 @@
],
});
}
function presentAlertAsyncHandler() {
openAlert({
header: 'Alert',
message: 'This is an alert with async handlers',
buttons: [
{
text: 'Confirm',
handler: () => {
return new Promise(async (resolve) => {
const loading = await loadingController.create({
message: 'Please wait...',
});
await loading.present();
setTimeout(async () => {
await loading.dismiss();
resolve();
}, 1000);
});
},
},
],
});
}
</script>
</body>
</html>