Skip to content

Commit 8e4783c

Browse files
feat(alert): accept Promise for button handler (#25702)
Resolves #25700 Co-authored-by: Sean Perkins <[email protected]>
1 parent 11c69c8 commit 8e4783c

File tree

4 files changed

+68
-9
lines changed

4 files changed

+68
-9
lines changed

core/src/components/alert/alert-interface.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,12 @@ export type AlertTextareaAttributes = { [key: string]: any };
5353
*/
5454
export type AlertInputAttributes = { [key: string]: any };
5555

56+
type AlertButtonOverlayHandler = boolean | void | { [key: string]: any };
57+
5658
export interface AlertButton {
5759
text: string;
5860
role?: 'cancel' | 'destructive' | string;
5961
cssClass?: string | string[];
6062
id?: string;
61-
handler?: (value: any) => boolean | void | { [key: string]: any };
63+
handler?: (value: any) => AlertButtonOverlayHandler | Promise<AlertButtonOverlayHandler>;
6264
}

core/src/components/alert/alert.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -335,24 +335,24 @@ export class Alert implements ComponentInterface, OverlayInterface {
335335
forceUpdate(this);
336336
}
337337

338-
private buttonClick(button: AlertButton) {
338+
private async buttonClick(button: AlertButton) {
339339
const role = button.role;
340340
const values = this.getValues();
341341
if (isCancel(role)) {
342342
return this.dismiss({ values }, role);
343343
}
344-
const returnData = this.callButtonHandler(button, values);
344+
const returnData = await this.callButtonHandler(button, values);
345345
if (returnData !== false) {
346346
return this.dismiss({ values, ...returnData }, button.role);
347347
}
348-
return Promise.resolve(false);
348+
return false;
349349
}
350350

351-
private callButtonHandler(button: AlertButton | undefined, data?: any) {
351+
private async callButtonHandler(button: AlertButton | undefined, data?: any) {
352352
if (button?.handler) {
353353
// a handler has been provided, execute it
354354
// pass the handler the values from the inputs
355-
const returnData = safeCall(button.handler, data);
355+
const returnData = await safeCall(button.handler, data);
356356
if (returnData === false) {
357357
// if the return value of the handler is false then do not dismiss
358358
return false;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { expect } from '@playwright/test';
2+
import { test } from '@utils/test/playwright';
3+
4+
test.describe('alert: basic', () => {
5+
test.beforeEach(async ({ page }) => {
6+
await page.goto('/src/components/alert/test/basic');
7+
});
8+
9+
test('should dismiss when async handler resolves', async ({ page }) => {
10+
const ionAlertDidPresent = await page.spyOnEvent('ionAlertDidPresent');
11+
const ionAlertDidDismiss = await page.spyOnEvent('ionAlertDidDismiss');
12+
const ionLoadingDidDismiss = await page.spyOnEvent('ionLoadingDidDismiss');
13+
14+
const alert = page.locator('ion-alert');
15+
16+
await page.click('#asyncHandler');
17+
await ionAlertDidPresent.next();
18+
19+
await page.click('.alert-button');
20+
21+
await expect(alert).toBeVisible();
22+
23+
await ionLoadingDidDismiss.next();
24+
await ionAlertDidDismiss.next();
25+
26+
await expect(alert).toBeHidden();
27+
});
28+
});

core/src/components/alert/test/basic/index.html

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
1515
</head>
1616
<script type="module">
17-
import { alertController } from '../../../../dist/ionic/index.esm.js';
17+
import { alertController, loadingController } from '../../../../dist/ionic/index.esm.js';
1818
window.alertController = alertController;
19+
window.loadingController = loadingController;
1920
</script>
2021

2122
<body>
@@ -30,9 +31,12 @@
3031
<ion-button id="basic" expand="block" onclick="presentAlert()">Alert</ion-button>
3132
<ion-button id="longMessage" expand="block" onclick="presentAlertLongMessage()">Alert Long Message</ion-button>
3233
<ion-button id="multipleButtons" expand="block" onclick="presentAlertMultipleButtons()"
33-
>Multiple Buttons (>2)</ion-button
34-
>
34+
>Multiple Buttons (>2)
35+
</ion-button>
3536
<ion-button id="noMessage" expand="block" onclick="presentAlertNoMessage()">Alert No Message</ion-button>
37+
<ion-button id="asyncHandler" expand="block" onclick="presentAlertAsyncHandler()"
38+
>Alert Async Handler</ion-button
39+
>
3640
<ion-button id="confirm" expand="block" onclick="presentAlertConfirm()">Confirm</ion-button>
3741
<ion-button id="prompt" expand="block" onclick="presentAlertPrompt()">Prompt</ion-button>
3842
<ion-button id="radio" expand="block" onclick="presentAlertRadio()">Radio</ion-button>
@@ -46,6 +50,7 @@
4650
--min-width: 0;
4751
--max-width: 200px;
4852
}
53+
4954
#delete-button {
5055
color: #eb445a;
5156
}
@@ -351,6 +356,30 @@
351356
],
352357
});
353358
}
359+
360+
function presentAlertAsyncHandler() {
361+
openAlert({
362+
header: 'Alert',
363+
message: 'This is an alert with async handlers',
364+
buttons: [
365+
{
366+
text: 'Confirm',
367+
handler: () => {
368+
return new Promise(async (resolve) => {
369+
const loading = await loadingController.create({
370+
message: 'Please wait...',
371+
});
372+
await loading.present();
373+
setTimeout(async () => {
374+
await loading.dismiss();
375+
resolve();
376+
}, 1000);
377+
});
378+
},
379+
},
380+
],
381+
});
382+
}
354383
</script>
355384
</body>
356385
</html>

0 commit comments

Comments
 (0)