Skip to content

Commit

Permalink
feat(alert): accept Promise for button handler (#25702)
Browse files Browse the repository at this point in the history
Resolves #25700

Co-authored-by: Sean Perkins <[email protected]>
  • Loading branch information
EinfachHans and sean-perkins authored Aug 3, 2022
1 parent 11c69c8 commit 8e4783c
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 9 deletions.
4 changes: 3 additions & 1 deletion core/src/components/alert/alert-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
}
10 changes: 5 additions & 5 deletions core/src/components/alert/alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
28 changes: 28 additions & 0 deletions core/src/components/alert/test/basic/alert.e2e.ts
Original file line number Diff line number Diff line change
@@ -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();
});
});
35 changes: 32 additions & 3 deletions core/src/components/alert/test/basic/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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>
Expand All @@ -46,6 +50,7 @@
--min-width: 0;
--max-width: 200px;
}

#delete-button {
color: #eb445a;
}
Expand Down Expand Up @@ -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>

0 comments on commit 8e4783c

Please sign in to comment.