How to hold back twice to exit

ehhhm yeah because you do not need to set lastBack, when you found something to close :wink:

But the purpose of the lastBack is to see when the button was last pressed, and if it was pressed within the past 500ms we don’t want to show the toast or exit the app, in case they were spamming the back button to just go back to the root :stuck_out_tongue: So it needs to be set after each press, otherwise it’s pretty much pointless to have it at all. I suppose it could be renamed to lastPress or something, cause it doesn’t actually resemble when we last went back a page, but when the last press was in general.

What is lastBack?

lastBack = Date.now();

thank you so much, it’s work for me.

red mark on allowClose …
how to define allowClose?
thanks in advance

Found your answer and took the liberty to change it and perhaps make a little neater :smiley:
It worked perfectly for my use case… thanks.

Here we go…

platform.registerBackButtonAction(() => {
      // getActiveNav is being deprecated so, fetch the first available nav.
      const nav = app.getActiveNavs()[0]; 
      const active = nav.getActive();

      let closeDelay = 2000;
      let spamDelay = 500;

      if (active.isOverlay) {
        // Checks if is dismissing something..
        // avoid exceptions if user spams back-button and stack isn't finished dismissing view yet.
        if (!this.dismissing) { 
          active.dismiss().then(() => this.dismissing = false);
        }
        this.dismissing = true;
      } else if (((Date.now() - this.lastBack) < closeDelay) &&
        (Date.now() - this.lastBack) > spamDelay) {
        // Leaves app if user pressed button not faster than 500ms a time, 
        // and not slower than 2000ms a time.
        platform.exitApp();
      } else {
        if (!this.spamming) { // avoids multiple toasts caused by button spam.
          let t = toast.create({
            message: "Pressione novamente para sair..",
            duration: closeDelay,
            dismissOnPageChange: true
          });
          t.onDidDismiss(() => this.spamming = false);
          t.present();
        }
        this.spamming = true;
      }

      this.lastBack = Date.now();
    });
1 Like

Thanks it’s works just perfect! :slight_smile:

where or in which file i can add this code?

Hi @mich356c,
The solution which you provided is not working for me. My use case is, I have an app where I have used ion-tabs for creating tabs for 4 different pages. And on these 4 pages, I have several pages which I open as a modal (which is an overlay and not a page, so can’t pop it). So, on using your code, if I click back button on any of 4 pages, it presents me the “Alert box to exit app” (works just fine), but when I open any modal on any pages and click back button to close it, it just don’t work. Also, after clicking the back button on modal, and then coming back to page and then clicking again the back button doesn’t brings the “Alert box to exit app” (which was working fine before I open any modal).
I am really stuck in all this, I really didn’t find any good solution which can close my modals on clicking back button and brings “Alert box to exit app” on clicking back button on root page.
Please help :slight_smile:

The code which I am using is:

app.component.ts

    platform.registerBackButtonAction(() => {
        let overlay = this.app._appRoot._overlayPortal.getActive();
        let nav = this.app.getActiveNavs()[0];

        if (overlay && overlay.dismiss) {
          overlay.dismiss();
          console.log('overlay dismissed');
        } else if (nav.canGoBack()) {
          nav.pop();
          console.log('nav popped');
        } else {
          if (this.alertShown == false) {
            this.presentConfirm();
            console.log('exit box presented');
          }
          else {
            this.alertShown = false;
            this.alert.dismiss();
            console.log('exit box rejected');
          }
        }
      });




  presentConfirm() {
    this.alertShown = true;
    this.alert = this.alertCtrl.create({
      title: 'Confirm Exit',
      message: 'Do you want to exit app?',
      buttons: [
        {
          text: 'Cancel',
          role: 'cancel',
          handler: () => {
            console.log('Cancel clicked');
            this.alertShown = false;
          }
        },
        {
          text: 'Yes',
          handler: () => {
            console.log('Yes clicked');
            this.platform.exitApp();
          }
        }
      ]
    });
    this.alert.present();
    // alert.present().then(() => {
    //   this.alertShown = true;
    // });
  }

can you tell me what is this.ionicApp here to access _overlayPortal as it is showing me error as Property ‘ionicApp’ does not exist on type

You need to import
import { App } from ‘ionic-angular’;

2 Likes

hey guys,

i don’t know if this is still relevant but I discovered something I couldn’t find in over a year of googling. In order to have the cleanest way possible to handle back button quit without having to mess with back-button defaults, use this snippet:

good luck :slight_smile:

        this.oldexitappfn = this.platform.exitApp;
        this.platform.exitApp = () => {
            if (/* condition to exit app is present */) {
                this.platform.exitApp = this.oldexitappfn;
                this.platform.exitApp();
            } else {
                /* don't exit and do something else */
            }
        }

I found this out without any reference online so this might be the first one, and it works :slight_smile:

I guess we have different notions of “clean”, because what you have posted goes to the heart of one of the things I hate the most about JavaScript: the ability to reach inside the internals of other entities and change their behavior. IMHO, one should never ever do anything like this.

Back in the days of old 68K MacOS, we called this technique “trap head patching”, and it was the cause of INIT conflict hell that greatly undermined the stability of the OS. Platform belongs to the framework; it does not belong to application code, and application code should not modify its internals.

When a publicly documented method like registerBackButtonAction exists, use it, instead of poking around in framework guts.

i can tell you what the problem is, The problem is Ionic.

They offer all the nice things like cool standards for mobile UI and everything else and it drags you for months and months into dev when you realize you hit a wall. In my case that wall was Tabs.

In order to push pages OUT of the tabs i needed to use nav.parent.parent.push all over the app, which resulted in the creation of multiple rootNavs which are not retrievable in the Ionic code so I can’t check if any pages are pushed before i unload the app using the global override of the back button method.

Why i say clean? well, it’s because the provided method probably doesn’t suit the majority of the developers. Why would I want to override the button throughout the entire app when usually I just want to override it in one-specific-very-specific-case. Unfortunately Ionic doesn’t provide that. They could’ve but they didn’t.

I understand where your concern comes from, but all I can say is: use at your own risk (which is very low risk)

Thanks

I hit that wall as well, and after lots of reflection decided that what I was trying to do wasn’t a good fit for the UI contract that tabs present. When I restricted my use of tabs to situations where it naturally fit and I did not get frustrated, I became much happier. In any situation where something that looks sort of like tabs was desired, I have found segments very useful.

This confuses me, because Platform is an app-wide singleton. When you assign directly to its prototype in one place, I would expect that to affect everything app-wide, exactly as patching a Toolbox A-trap affected everything running on the machine.

If you want to modify back button behavior only in one specific place (such as when a particular page is active), what I would do is to use lifecycle events on that page to register and deregister the custom back button action, thereby insulating the rest of the app from any unexpected effects. I have used that approach to get around a bug involving back buttons and modal dialogs.

well obviously if i want to manipulate the back button on one specific page the “cleaner” method is to use the Ionic given lifecycle methods such as IonViewWillUnload for example. In my case i only manipulated the exitApp() method which AFAIK only is called when the app is about to leave through the back button :smiley:

Anyway, to keep this short, you are right, I don’t prefer altering the guts of the framework but you gotta do what you gotta do, and in this case it’s not a super crucial method being used throughout the app so yeah, if you like it use it, if you don’t then don’t. I wish someone would’ve shown me this snippet a year ago TBH.

Hi, I am using Ionic v4 and in Platform class has no method with exitApp(), how could exit app when clicked back button twice?
thnks

I retract my comments about how to override the back button on exit, it is very unreliable. sorry @rapropos, you were right :slight_smile: I did however find a way to override the back button and revert it to the old state when i don’t need it and I also published a package on npm that makes it easier to use these functions. I only started this project today and published it also today so I did minimal testing on it, but the functions that matter do work.
take a look:
https://www.npmjs.com/package/ionic3-android-backbutton

My code says “Property this.lastBack does not exist on type 'HomePage”, I need to import something else?