Ionic-framework: Close modal using back button (especially on PWAs)

Created on 6 Feb 2018  路  6Comments  路  Source: ionic-team/ionic-framework

Ionic version: (check one with "x")
(For Ionic 1.x issues, please use https://github.com/ionic-team/ionic-v1)
[ ] 2.x
[x] 3.x
[ ] 4.x

I'm submitting a ... (check one with "x")
[ ] bug report
[x] feature request

Current behavior:
If there's an open ModalController modal and the user presses the back button (either the hardware back button on Android or the history back button in PWA), the modal stays open and the page navigates back.

Expected behavior:
The modal should close when the user presses the back button.

Steps to reproduce:
Open a Modalcontroller modal, press the back button, notice that the modal does not close but the page behind it navigates back.

Related code:

Other information:

Ionic info: (run ionic info from a terminal/cmd prompt and paste output below):

> ionic info

cli packages: (C:\Users\[redacted]\app\node_modules)

    @ionic/cli-utils  : 1.19.0
    ionic (Ionic CLI) : 3.19.0

global packages:

    cordova (Cordova CLI) : not installed

local packages:

    @ionic/app-scripts : 3.1.6
    Cordova Platforms  : browser 5.0.3
    Ionic Framework    : ionic-angular 3.9.2

System:

    Android SDK Tools : 26.1.1
    Node              : v6.12.3
    npm               : 5.6.0
    OS                : Windows 10

Environment Variables:

    ANDROID_HOME : C:\Android

Misc:

    backend : legacy
v3

Most helpful comment

Yup that's something we've been running into for a while now...

I found a solution for my PWApps.

In app.component.ts call a function in your constructor named backButtonListener()

And here is the code for this function:

backButtonListener(): void {
    window.onpopstate = (evt) => {
      // Close any active modals or overlays
      let activePortal = this._ionicApp._loadingPortal.getActive() ||
        this._ionicApp._modalPortal.getActive() ||
        this._ionicApp._toastPortal.getActive() ||
        this._ionicApp._overlayPortal.getActive();
      if (activePortal) {
        activePortal.dismiss();
        return;
      }
    }
  }

That will close the modal on a back button press. But the app will still navigate back. To prevent this here is a quick workaround...

In your modal's constructor (or ngOnInit or ionDidViewEnter...) add this 2 lines:

var foo = { foo: true };
history.pushState(foo, "Anything", " "); // Put something to history for back button

As something is added to user's history, the NavPop event will remove something you just added.

This makes the app weird if you close multiple modals using a button and then try to navigate back using back button but I think it's still better than the Ionic actual behavior...

Hope this helps!

All 6 comments

Yup that's something we've been running into for a while now...

I found a solution for my PWApps.

In app.component.ts call a function in your constructor named backButtonListener()

And here is the code for this function:

backButtonListener(): void {
    window.onpopstate = (evt) => {
      // Close any active modals or overlays
      let activePortal = this._ionicApp._loadingPortal.getActive() ||
        this._ionicApp._modalPortal.getActive() ||
        this._ionicApp._toastPortal.getActive() ||
        this._ionicApp._overlayPortal.getActive();
      if (activePortal) {
        activePortal.dismiss();
        return;
      }
    }
  }

That will close the modal on a back button press. But the app will still navigate back. To prevent this here is a quick workaround...

In your modal's constructor (or ngOnInit or ionDidViewEnter...) add this 2 lines:

var foo = { foo: true };
history.pushState(foo, "Anything", " "); // Put something to history for back button

As something is added to user's history, the NavPop event will remove something you just added.

This makes the app weird if you close multiple modals using a button and then try to navigate back using back button but I think it's still better than the Ionic actual behavior...

Hope this helps!

@alaborderie _ionicApp does not seem to exist in my App object.

edit: never mind. Got it. I needed to inject it into the class.

import { IonicApp } from 'ionic-angular';
[...]
  constructor(private ionicApp: IonicApp, [...]) { 

Is this something that will be solved in the future? Because for me it feels more like a bug than a feature request, because when I open a modal and press the hardware back button on my smartphone the page beyond the modal, which is not visible due to the modal, gets pushed back instead, which feels weird and I currently can't see a usecase when this behavior would make sense.

Thank you!

Same here.
I'm on Ionic V4 and can't find IonicApp to import. Is IonicApp gone in V4? If so, this workaround isn't suitable for V4

This issue has been automatically identified as an Ionic 3 issue. We recently moved Ionic 3 to its own repository. I am moving this issue to the repository for Ionic 3. Please track this issue over there.

If I've made a mistake, and if this issue is still relevant to Ionic 4, please let the Ionic Framework team know!

Thank you for using Ionic!

Was this page helpful?
0 / 5 - 0 ratings