Hardware back button with Ionic 4

Here’s my workaround:

import { ModalController } from '@ionic/angular';
import { Injectable } from '@angular/core';
import { CanDeactivate, Router, ActivatedRouteSnapshot } from '@angular/router';
import { Location } from '@angular/common';

@Injectable({
  providedIn: 'root'
})
export class BackButtonService implements CanDeactivate<any> {

  constructor( 
    private modalCtrl: ModalController,
    private alertCtrl: AlertController,
    private popoverCtrl: PopoverController,
    private readonly location: Location,
    private readonly router: Router) { }

  canDeactivate(component: any, currentRoute: ActivatedRouteSnapshot): Promise<boolean> {
    return new Promise((resolve) => {
      this.modalCtrl.getTop()
      .then((modalElement) => {
        if (modalElement) {
          modalElement.dismiss();
          const currentUrlTree = this.router.createUrlTree([], currentRoute);
          const currentUrl = currentUrlTree.toString();
          this.location.go(currentUrl);
          resolve(false);
        } else {
          this.alertCtrl.getTop()
          .then((alertElement) => {
            if (alertElement) {
              alertElement.dismiss();
              const currentUrlTree = this.router.createUrlTree([], currentRoute);
              const currentUrl = currentUrlTree.toString();
              this.location.go(currentUrl);
              resolve(false);
            } else {
              this.popoverCtrl.getTop()
              .then((popoverElement) => {
                if (popoverElement) {
                  popoverElement.dismiss();
                  const currentUrlTree = this.router.createUrlTree([\*], currentRoute);
                  const currentUrl = currentUrlTree.toString();
                  this.location.go(currentUrl);
                  resolve(false);
                } else {
                  resolve(true);
                }
              });
            }
          });
        }
      });
    });
  }
}

In App-routing.module.ts:

  {
    path: 'subpage',
    loadChildren: './subpage/subpage.module#SubpagePageModule',
    canDeactivate: [BackButtonService]
  },

This is enough in my case. You can certainly extend it to other types (menus, alerts, etc).

Hai GameAppsBD .This is not working in tabs home page ,But it is working fine in login page.Here is my code

backButtonEvent(){
this.platform.backButton.subscribe(async () => {
// close action sheet
try {
const element = await this.actionSheetCtrl.getTop();
if (element) {
element.dismiss();
return;
}
} catch (error) {
}

  this.routerOutlets.forEach((outlet: IonRouterOutlet) => {
      if (outlet && outlet.canGoBack()) {
          outlet.pop();

      } else  {
          if (new Date().getTime() - this.lastTimeBackPress < this.timePeriodToExit) {
              // this.platform.exitApp(); // Exit from app
              navigator['app'].exitApp(); // work in ionic 4

          } else {
            this.showAlert()
              this.lastTimeBackPress = new Date().getTime();
          }
      }
  });
  this.lastBack = Date.now();

});
}

This is not Working in Tabs Home Page.Working Fine in Login Page . Here is my code`.Please Help Me

  backButtonEvent(){
    this.platform.backButton.subscribe(async () => {
      // close action sheet
      try {
          const element = await this.actionSheetCtrl.getTop();
          if (element) {
              element.dismiss();
              return;
          }
      } catch (error) {
      }

      this.routerOutlets.forEach((outlet: IonRouterOutlet) => {
          if (outlet && outlet.canGoBack()) {
              outlet.pop();

          } else  {
              if (new Date().getTime() - this.lastTimeBackPress < this.timePeriodToExit) {
                  navigator['app'].exitApp(); // work in ionic 4

              } else {
                this.showAlert()
                  this.lastTimeBackPress = new Date().getTime();
              }
          }
      });
      this.lastBack = Date.now();
  });
  }

My app doesn’t close when hitting the backButton in the homePage. I tried this :

backButtonEvent(){
       this.platform.backButton.subscribe(()=>{
       navigator['app'].exitApp();
    })

And it works…
But it also works in the other pages, so instead of having the normal “back” behaviour, the backButton exits the app from everywhere in the app…

I had the idea of unsubscribing when moving from the homepage, but the problem is that when I go back to the home page, the ngOnInit is not fired, so I can’t resubscribe…

Another idea is to access the name of the page where the user is (router??) from the backButtonEvent function, to know which behaviour to have

Had you this sort of problem, did you solve it ??

Thanks

Any solution so far? I still have the same problem, being on the root page the back button does not work to close the application, and add navigator [“app”]. exitapp () the application is left on any page that is

I found a solution here :
https://forum.ionicframework.com/t/v4-back-button-doesnt-exit-app-solved-tutorial/149994

Thank you, It’s work me, and i’m doing small changes in my code , change in If condition this.router.isActive(’/home’,true),

ex:
if (this.router.url === ‘/home’)
To
if (this.router.isActive(’/home’,true) )

Dear in my case, this update works perfectlly.

 try {
     const element = await this.menu.getOpen();
     if (element !== null && element !== undefined)
          this.menu.close();
          return;
     }
 } catch (error) {
   }

please note updated line here if (element !== null && element !== undefined) because menu.getOpen() does not return null as per it’s documentation and always exceutes this if block regarless of menu behaviour so code after this try catch block is always skipped. instead its undefined when menu is closed. I think its bug

This may help.

Works fine, but having one issue. Let’s say my App’s home page is Services.

Now I’m checking this 3 case:

  1. If i’m on Services page, pressing back-button then it shows toast. => WORKS AS EXPECTED
  2. If i navigate to Login page from Services, then In Login page, i’m pressing back-button then it goes back to Services page and shows toast. => NOT WORK AS EXPECTED
    (It should not display toast)
  3. If i navigate to Register page from Login, then In Register page, i’m pressing back-button then it goes back to Login page and again it goes back to Services page. => NOT WORK AS EXPECTED
    (It should only navigate to Login page)

Please help ASAP!

Thanks,
Nirav

Can anyone tell me about this line :
@ViewChildren(IonRouterOutlet) routerOutlets: QueryList<IonRouterOutlet>

What is that? Is i have to give id or name to my ion-router-outlet tag?

Add this code in app.component.ts

import { Component, OnInit, ViewChildren, QueryList } from ‘@angular/core’;
import { Platform, IonRouterOutlet } from ‘@ionic/angular’;
import { SplashScreen } from ‘@ionic-native/splash-screen/ngx’;
import { StatusBar } from ‘@ionic-native/status-bar/ngx’;
import { Router } from ‘@angular/router’;

@Component({
selector: ‘app-root’,
templateUrl: ‘app.component.html’,
})

export class AppComponent implements OnInit {

@ViewChildren(IonRouterOutlet) routerOutlets: QueryList;

constructor(
    private platform: Platform,
    private splashScreen: SplashScreen,
    private statusBar: StatusBar,
    public router: Router,
) {
    this.initializeApp();
    this.backButtonEvent();
}

ngOnInit() { }

backButtonEvent() {
    this.platform.backButton.subscribe(() => {
        this.routerOutlets.forEach((outlet: IonRouterOutlet) => {
            if (this.router.url === '/home') {
                navigator['app'].exitApp();
            } else {
                window.history.back();
            }
        });
    });
}

initializeApp() {
    this.platform.ready().then(() => {
        this.statusBar.styleDefault();
        this.splashScreen.hide();
    });
}

}

I get error in routerOutlets.forEach.
vendor.js:51643 ERROR Error: Uncaught (in promise): TypeError: this.routerOutlets.forEach is not a function TypeError: this.routerOutlets.forEach is not a function at AppComponent.<anonymous> (main.js:1130) at step (vendor.js:106764) at Object.next (vendor.js:106745) at fulfilled (vendor.js:106735) at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (polyfills.js:2749) at Object.onInvoke (vendor.js:53218) at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (polyfills.js:2748) at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (polyfills.js:2508) at polyfills.js:3247 at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (polyfills.js:2781) at resolvePromise (polyfills.js:3189) at polyfills.js:3099 at fulfilled (vendor.js:106735) at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (polyfills.js:2749) at Object.onInvoke (vendor.js:53218) at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (polyfills.js:2748) at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (polyfills.js:2508) at polyfills.js:3247 at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (polyfills.js:2781) at Object.onInvokeTask (vendor.js:53209)

Never mind that, I forgot to change ViewChild to ViewChildren but now I have a problem when i dismiss a page. The outlet.pop() and the Toast function triggers at the same time.

Hi,
All except the part this.routerOutlets.forEach((outlet: IonRouterOutlet) => {}) is working. Control is not moving inside this. Please help

Add this in tab1/Home page

lastTimeBackPress = 0;
timePeriodToExit = 2000;

constructor(){
this.platform.backButton.subscribe(async() => {
if (new Date().getTime() - this.lastTimeBackPress < this.timePeriodToExit) {
navigator[‘app’].exitApp(); // work in ionic 4
} else if (this.router.url === ‘/tabs/tab1’) {
this.matBar.open(‘Press back again to exit App’, ‘2000’, {
duration: 2000,
});
this.lastTimeBackPress = new Date().getTime();
}
});
}

Hi, I have to handle same scenario with hardware back button to exit the app when user clicks back button from home page and should not take it to login page as user already logged In. I tried your solution placing code in app.component.ts but it did not work for me… Could you please help in getting this done by providing sample application code(complete application)
export class AppComponent {
@ViewChild(IonRouterOutlet) routerOutlet: IonRouterOutlet;

constructor(
private platform: Platform,
private splashScreen: SplashScreen,
private statusBar: StatusBar,
private router: Router,
private commonService: CommonService
) {
this.initializeApp();
this.platform.backButton.subscribeWithPriority(0, () => {
alert(this.router.url);
if (this.routerOutlet && this.routerOutlet.canGoBack()) {
this.routerOutlet.pop();
} else if (this.router.url === ‘/login’) {
// this.platform.exitApp();
// or if that doesn’t work, try
navigator[‘app’].exitApp();
} else {
this.commonService.showAlert(‘Exit’);
}
});
}

Hi,

to prevent navigating back to login page i simply set the root navigation at login:

 //Check if user is logged-in; if so the dashboard will be loaded otherwise the login-page
            this.authenticationService.authenticationState.subscribe(state => {
                if (state) {
                    this.navController.navigateRoot(['menu/tabs/dashboard']);
                } else {
                    this.navController.navigateRoot('login')
                }
            });

By setting the root there is no possibility to navigate back to another page.

import { App} from ‘ionic-angular’;

constructor(private app: App) {

this.backbutton()

}

backbutton() {

this.platform.ready().then(() => {

  //Registration of push in Android and Windows Phone
  this.platform.registerBackButtonAction(() => {
   let nav = this.app.getActiveNav();
    if (nav.canGoBack()){ //Can we go back?
     nav.pop();
   

    }else{
      
      
     
      this.navCtrl.pop()
      
     
    }
  });
});

}

How is it possible to use the hardware back button to navigate through tabs?

import { Component, OnInit, ViewEncapsulation, ViewChildren, QueryList } from '@angular/core';
import { Events, MenuController, Platform, IonRouterOutlet, ActionSheetController, PopoverController, ModalController } from '@ionic/angular';
import { Toast } from '@ionic-native/toast/ngx';

export class AppComponent implements OnInit {

  @ViewChildren(IonRouterOutlet) routerOutlets: QueryList<IonRouterOutlet>;

  lastTimeBackPress = 0;
    timePeriodToExit = 2000;
constructor(
    private menu: MenuController,
    private platform: Platform,
    private router: Router,
    private push: Push,
    public toastCtrl: ToastController,
    private actionSheetCtrl: ActionSheetController,
    private popoverCtrl: PopoverController,
    public modalCtrl: ModalController,
    private toast: Toast
  ) {    
    this.backButtonEvent();
  }
backButtonEvent() {
    this.platform.backButton.subscribe(async () => {
        // 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) {

        }

        this.routerOutlets.forEach((outlet: IonRouterOutlet) => {
            if (outlet && outlet.canGoBack()) {
                outlet.pop();

            } else if (this.router.url === '/login') {
                if (new Date().getTime() - this.lastTimeBackPress < this.timePeriodToExit) {
                    // this.platform.exitApp(); // Exit from app
                    navigator['app'].exitApp(); // work for ionic 4

                } else {
                    this.toast.show(
                        `Press back again to exit App.`,
                        '2000',
                        'center')
                        .subscribe(toast => {
                            // console.log(JSON.stringify(toast));
                        });
                    this.lastTimeBackPress = new Date().getTime();
                }
            }
        });
    });
}

It works for me and I think it will help you too. If it works give a heart. Thanks.