Hi,
I am new to Ionic 4, I have managed to implement a PWA using ionic 4 with Angular.
I am having a hard time figuring out how to close modals/Alerts/ActionSheets on back-button on browser (Desktop & mobile) when served as a PWA. When I press back when a modal is open, the modal stays open and background page is navigated back.
I have tried workarounds from different forums and posts like
Thank you for the response.
but I wanted to know, how we can trigger dismiss method on hardware back button on device and on desktop browser back navigation button is pressed.
@aaronksaunders answer is useless. Have you even read his question ?
@akshay_kanchan, did you find a solution to this issue ? I’m running into the same issue as you do.
I’m looking for a proper way to have physical backbutton and back on the browser closes modals. Can’t find a solution that fully works. Does somebody has a solution ?
@connois your response to me obviously misreading the question is a bit rude and over the top. I have been supporting this community for years, so please forgive me if I make a mistake here or there no one is perfect, but that doesn’t meant you cannot be professional
@connois, Sorry for delayed response but I did get it worked with following code in app.component’s constructor and creating a service as shown below.
app.component
// close all popovers on back navigation, if open.
this.router.events.subscribe((event: any): void => {
if (event instanceof NavigationStart) {
if (event.navigationTrigger === 'popstate') {
this.autocloseOverlaysService.trigger();
}
}
});
AutocloseOverlaysService
import { Injectable, ViewChildren, QueryList } from '@angular/core';
import { IonRouterOutlet, ActionSheetController, PopoverController, ModalController, MenuController, ToastController } from '@ionic/angular';
import { Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AutocloseOverlaysService {
@ViewChildren(IonRouterOutlet) routerOutlets: QueryList<IonRouterOutlet>;
lastTimeBackPress = 0;
timePeriodToExit = 2000;
constructor(
private actionSheetCtrl: ActionSheetController,
private popoverCtrl: PopoverController,
private modalCtrl: ModalController,
private menu: MenuController,
private router: Router,
private toastController: ToastController
) { }
async trigger() {
console.log('backbutton triggered');
// close action sheet
try {
const element = await this.actionSheetCtrl.getTop();
if (element) {
element.dismiss();
return;
}
} catch (error) {
}
// close popover
try {
const element = await this.popoverCtrl.getTop();
if (element) {
element.dismiss();
return;
}
} catch (error) {
}
// close modal
try {
const element = await this.modalCtrl.getTop();
if (element) {
element.dismiss();
return;
}
} catch (error) {
console.log(error);
}
// close side menua
try {
const element = await this.menu.getOpen();
if (element !== null) {
this.menu.close();
return;
}
} catch (error) {
}
}
}
You are right. Words came out rude when I didn’t meant them like this. English is not my native language and sometime words come out wrong. Forgive me. WiIl be more careful.
Works good, however, it will still navigate back in addition to closing the modal, in my case i would only want it to close the modal, is there a way to stop it from navigating within the router.events.subscribe perhaps?
Now it will only close the modal, and not trigger a route change in angular. And multiple opening of modals (and closing with a button) only leaves one state in the history.
Hey, just in case anybody is looking for a different solution, here is mine.
I use canDeactivate guard to check if parent component can be deactivated. If modal is open, canDeactivate returns false and closes the modal, but does not navigate back from parent component.
The only Issue I had is that the DeactivateGuard needs to be @Injectable() and in the app.module.ts you need to add the guard inside the providers array… nevertheless it works like a charm, thank you so much
@akshay_kanchan your solution is working partially. Pressing back button will dismiss the modal but also going to the previous page. Any solution?
Using ionic 5, angular 12
Hey Sorry for delayed response, in theory if you modify the AutocloseOverlaysService service code to return boolean value that is, when element exists (on any type of modal/popover) return false else return true and call this in canActivate guard, it should work as you per your requirements.
So the flow would be, if route change happens, code in the canActivate guard will execute the statement
example: return await this.autocloseOverlaysService.trigger(); and the trigger method will return boolean value which will tell angular whether the route should happen or not. So if Modal/Overlay was open the route will not happen.