Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alert before leaving page (navigate back) with Ionic v2

How do you show an alert, that the user must close, before going back to the previous page? I'm using the standard <ion-navbar *navbar> arrow button.

I tried hooking into the NavController event ionViewWillLeave like this, but it doesn't work:

ionViewWillLeave() {
  let alert = Alert.create({
    title: 'Bye',
    subTitle: 'Now leaving',
    buttons: ['OK']
  });
  this.nav.present(alert);
}

This shows the alert, but doesn't go back once it is closed. If I comment it out, the back button works fine.

like image 277
Anders Avatar asked Jun 21 '16 21:06

Anders


3 Answers

The accepted solution doesn't work in RC3, here's a new one using Nav Controller's Nav Guard:

ionViewCanLeave(): Promise<void> {
  return new Promise((resolve, reject) => {
    let confirm = this.alertCtrl.create({
      title: 'Are you sure?',
      message: 'Bunnies will die :(',
      buttons: [{
        text: 'OK',
        handler: () => {
          resolve();
        },
      }, {
        text: 'Cancel',
        handler: () => {
          reject();
        }
      }],
    });
    confirm.present();
  })
}

If you are navigating using push() on the nav controller, you also need to do a catch on it otherwise it will throw an unhandled error:

this.navCtrl.push(SomePage).catch(() => {});
like image 169
Boštjan Pišler Avatar answered Oct 29 '22 22:10

Boštjan Pišler


UPDATE

As of Ionic2 RC, now we can use Nav Guards.

In some cases, a developer should be able to control views leaving and entering. To allow for this, NavController has the ionViewCanEnter and ionViewCanLeave methods. Similar to Angular 2 route guards, but are more integrated with NavController

So now we can do something like this:

someMethod(): void {
    // ...
    this.showAlertMessage = true;
}

ionViewCanLeave() {
    if(this.showAlertMessage) {
        let alertPopup = this.alertCtrl.create({
            title: 'Exit',
            message: '¿Are you sure?',
            buttons: [{
                    text: 'Exit',
                    handler: () => {
                        alertPopup.dismiss().then(() => {
                            this.exitPage();
                        });         
                    }
                },
                {
                    text: 'Stay',
                    handler: () => {
                        // need to do something if the user stays?
                    }
                }]
        });

        // Show the alert
        alertPopup.present();

        // Return false to avoid the page to be popped up
        return false;
    }
}

private exitPage() {
    this.showAlertMessage = false;
    this.navCtrl.pop();
}

I prefer to use the this.showAlertMessage property, so we can have more control over when we need to show the alert if the user tries to exit the page. For instance, we may have a form in the page, and if the user didn't make any changes, we don't want to show the alert (this.showAlertMessage = false) and if the form was actually changed, we want to show the warning (this.showAlertMessage = true )


OLD ANSWER

After a few hours struggling with this, I've found the solution.

One issue that I had to face is that the ionViewWillLeave is executed also when the alert is closed so that makes things more complicated (when the view is about to be closed because you pressed the back button, the alert shows up, but when you click ok, that fires the event again and opens the alert again and so on...).

Another thing to keep in mind is that ActionSheets and Alerts get added to the navigation stack, so this.nav.pop() instead of removing the current view from the stack, removes the alert (and because of that we may feel it's not working properly).

That being said, the solution I've found is:

import {Component} from '@angular/core';
import {NavController, NavParams, Alert} from 'ionic-angular';

@Component({
    templateUrl: 'build/pages/mypage/mypage.html',
})
export class MyPage{

    // ....

    confirmedExit: boolean = false;

    constructor(private nav: NavController, navParams: NavParams) {
        // ...
    }

    ionViewWillLeave() {
        if(!this.confirmedExit) {
            let confirm = Alert.create({
                title: 'Bye',
                message: 'Now leaving',
                buttons: [
                {
                    text: 'Ok',
                    handler: () => {
                        this.exitPage();
                    }
                }
                ]
            });
            this.nav.present(confirm);
        }
    }

    public exitPage(){
        this.confirmedExit = true;
        this.nav.remove().then(() => {
            this.nav.pop();
        });
    }


  }

So:

  • I use a confirmedExit variable to know if you already clicked the ok button (so you confirmed you wanted to exit the page, and with that I know that the next time the ionViewWillLeave event is fired, I don't have to show the alert)
  • In the exitPage method, first I do this.nav.remove() to remove the alert from the stack, and once that's done, we do the this.nav.pop() to go back to the previous page.

like image 30
sebaferreras Avatar answered Oct 29 '22 21:10

sebaferreras


this is my version of Bostjan answer, without throwing unhandled exception.

ionViewCanLeave(): Promise<boolean> {
    return new Promise(resolve => {
        if (!this.formGroup.dirty) return resolve(true);

        this._alertCtrl.create({
            title: 'Confirm leaving',
            message: 'There is unsave work, do you like to continue leaving?',
            buttons: [{
                text: 'Leave',
                handler: () => {
                    resolve(true);
                }
            }, {
                text: 'Stay',
                handler: () => {
                    resolve(false);
                }
            }]
        }).present();
    });
}
like image 36
zer09 Avatar answered Oct 29 '22 23:10

zer09