#Ionic Angular app, catch browser back event

8 messages · Page 1 of 1 (latest)

junior wind
#

I have a Ionic Angular app for Android using Capacitor, but the same codebase also for PWA (web).

Now on a certain page I want to catch the default back event (when an user clicks in the browser).
Instead of going a page back I want to catch it and show an Alert (ionic Alertcontroller).
This alertcontroller is also shown when I hit the hardware back button on a mobile device.

What is the best way to archive this (only for the browser part). ChatGTP gave me an HostListener example, but that didn't work as expected. The alert was show, but the page was also going back.

loud willow
#

By "Back" event, what are you referring to? The user clicking in the browser the "Go back one page" button?
In that case you'll need to take into account that there is no browser-API to do so.

What you can do is implement a "canDeactivate"-routeguard. As long as the back-button will route to another page within the angular-app, this will trigger the routeGuard within which you can trigger alert etc.

https://angular.dev/api/router/CanDeactivateFn?tab=description

The web development framework for building modern apps.

junior wind
#

Indeed the Go Back button in the browser. The flow is like follow Home > Create Game page > Play Game page. And on the Play Game page, an user can hit the back button on the browser (or the back button on the mouse). That's the one I want to catch and show a confirmation alert first (just like on Android, but there we have hardware back button).

loud willow
# junior wind Indeed the Go Back button in the browser. The flow is like follow Home > Create ...

You can't catch click events on that browser back button, that is fundamentally not possible.

You can trigger behavior when the user triggers routing in your application.
That one you can notice, as in scenarios where the "back"-Button leads to another page that is from your application.
Angular will notice the URL change and translate that into "Ah, I need to trigger routing".
For that scenario the correct API to use is a canDeactivate-Routeguard

#

The canDeactivate-Routeguard exists pretty much exactly for that purpose.
It answers the question "Is the user allowed to route away from this page?" During which you can also trigger side effects, such as triggering your alert.

junior wind
#

Thank you for your answer, I have come up with this

@Injectable({
providedIn: 'root',
})
export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {
constructor() {
}

canDeactivate(
component: CanComponentDeactivate
): Observable<boolean> | Promise<boolean> | boolean {
console.log(Capacitor.isNativePlatform(), component);

if (!Capacitor.isNativePlatform() && component !== null) {
  return component.exit(); // show the exit prompt if on web or desktop
}
return true; // allow navigation on non-web platforms

}
}

This seems to work if I remove the logic of the component. However the page where I add this guard to has a function exit()

async exit() {
const alert = await this.alertController.create({ .... etc

and that exit alert on the page is what I want to trigger instead of the default back.
if I test with this

if (!Capacitor.isNativePlatform()) {
return false; // show the exit prompt if on web or desktop
}

its indeed not going back, but adding the component (as given as example by ChatGTP) I get component = null and thus exit() is not defined.

Can you trigger the exit function from page using the guard ?

#

Reason why I want ot have it there is because the hardware button uses the same function exit()

loud willow
# junior wind Thank you for your answer, I have come up with this @Injectable({ providedIn:...

Without having read the code, as I got no time atm - You could

  1. Use a functional routeguard, that is a bit less verbose and more streamlined
  2. You can have a signal public hasConfirmedAlert = signal(false) in your component and when your user confirms leaving in your alert you can run
this.hasConfirmedAlert.set(true);
history.back()

In your guard you can then check

const myGuard: CanDeactivateFn = (component: YourComponent ...) => {
  ...
  if(!component.hasConfirmedAlert()){
    triggerAlert();
    return false
  } else {
    return true
  }
}