How to hold back twice to exit


#1

I try to learn from forum, But it looked like an old version of ionic2.

I can’t make it work with last Ionic2 version.

Like this code, I can registerBackButtonAction, And yes it’s work to hold back twice to exit application.

But in push page it can’t hold back to go back to last page.

      let rootScope = {
        backButtonPressedOnceToExit: false
      };
      this.platform.registerBackButtonAction(() => {
        if (rootScope['backButtonPressedOnceToExit']) {
          this.platform.exitApp();
        }
        else {
          rootScope['backButtonPressedOnceToExit'] = true;
          this.toastCtrl.create({
            message: "Press back button again to exit",
            duration: 2000
          }).present();
          setTimeout(()=>{
            rootScope['backButtonPressedOnceToExit'] = false;
          },2000);
        }
        return false;
      },101);

How to solve this problem?


#2

Here’s what I use

platform.registerBackButtonAction(() => {
	const overlayView = this.app._appRoot._overlayPortal._views[0];
	if(overlayView && overlayView.dismiss) {
		overlayView.dismiss();
	} else {
		let nav = this.app.getActiveNav();
		if(nav.canGoBack()){
			nav.pop();
		} else if(this.lastBack + 500 < Date.now()) {
			this.platform.exitApp();
		}
	}
	this.lastBack = Date.now();
});

The back button will

  • Dismiss modals/dialogs
  • Go back to the previous view in the nav stack
  • If in the root, close the application, UNLESS the user seems to have been spamming the back button (500ms delay)

E.g. if the user is in a nav stack with 3 pages, spams the back button to get back to the first one, the app wont close when he makes it to the last page. If he waits 500ms and clicks back again, it closes the app.

I hope I understood the question correctly and that this can be of use!


#3

i would do a little bit cleaup work:

checkout https://github.com/driftyco/ionic/issues/6982#issuecomment-254740855 how to retriev active view overlays and modals :wink:

platform.registerBackButtonAction(() => {
  const overlay = this.ionicApp._overlayPortal.getActive();
  const nav = this.app.getActiveNav();

  if (overlayView && overlayView.dismiss) {
    overlayView.dismiss();
    return;
  }
  if (nav.canGoBack()) {
    nav.pop();
    return;
  }
  if (Date.now() - this.lastBack < 500) {
    this.platform.exitApp();
  }
  this.lastBack = Date.now();
});

#4

Well, now it doesn’t set this.lastBack in order to prevent the app from being closed when the back button is being spammed, because of the returns :wink:

Edit: Cleaned it up and using this myself now

platform.registerBackButtonAction(() => {
	const overlay = this.app._appRoot._overlayPortal.getActive();
	const nav = this.app.getActiveNav();

	if(overlay && overlay.dismiss) {
		overlay.dismiss();
	} else if(nav.canGoBack()){
		nav.pop();
	} else if(Date.now() - this.lastBack > 500) {
		this.platform.exitApp();
	}
	this.lastBack = Date.now();
});

Edit 2: But yeah, if you want the app to exit when clicking twice, change the > 500 to < 500, 500 being the duration/delay. Though I personally think the behavior of not closing the app when the back button is being spammed is much better.

Edit 3: If you want to keep both the “don’t close on spam” and “close with 2 taps”, use this

platform.registerBackButtonAction(() => {
	const overlay = this.app._appRoot._overlayPortal.getActive();
	const nav = this.app.getActiveNav();
	const closeDelay = 2000;
	const spamDelay = 500;

	if(overlay && overlay.dismiss) {
		overlay.dismiss();
	} else if(nav.canGoBack()){
		nav.pop();
	} else if(Date.now() - this.lastBack > spamDelay && !this.allowClose) {
		this.allowClose = true;
		let toast = this.toastCtrl.create({
			message: this.translate.instant("general.close_toast"),
			duration: closeDelay,
			dismissOnPageChange: true
		});
		toast.onDidDismiss(() => {
			this.allowClose = false;
		});
		toast.present();
	} else if(Date.now() - this.lastBack < closeDelay && this.allowClose) {
		this.platform.exitApp();
	}
	this.lastBack = Date.now();
});

Not sure if there’s a neater way of writing that… lol


Unregister back button action
How to show toast before closing app in ionic latest version?
How to set double touch to exit app in ionic 2?
Confirm Exit with device back button in ionic
Hardware Backbutton Service
How to avoid the hardware back button to close a modal view in Android?
#5

What is this.app ?


#6
import { App } from 'ionic-angular';

#7

Wow, This work.
Thank you very much.


#8

Hey just an FYI, change

} else if(Date.now() - this.lastBack > spamDelay && Date.now() - this.lastBack < closeDelay && this.allowClose) {

to

} else if(Date.now() - this.lastBack < closeDelay && this.allowClose) {

otherwise if you tap the back button too fast after getting the toast, it wont close :stuck_out_tongue:


#9

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


#10

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.


#11

What is lastBack?


#12

lastBack = Date.now();


#13

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


#14

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


#15

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();
    });

#16

Thanks it’s works just perfect! :slight_smile:


#17

where or in which file i can add this code?


#18

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;
    // });
  }

#19

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


#20

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