使用 Ionic v2 在离开页面(返回)之前发出警报

Alert before leaving page (navigate back) with Ionic v2

如何显示 alert,用户必须在返回上一页之前关闭?我使用的是标准 <ion-navbar *navbar> 箭头按钮 .

我试过像这样连接到 NavController 事件 ionViewWillLeave,但它不起作用:

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

这会显示警报,但一旦关闭就不会返回。如果我把它注释掉,后退按钮就可以正常工作了。

更新

从 Ionic2 RC 开始,现在我们可以使用 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

所以现在我们可以这样做:

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

我更喜欢使用 this.showAlertMessage 属性,这样我们可以更好地控制在用户尝试退出页面时何时需要显示警报。例如,我们可能在页面中有一个表单,如果用户没有进行任何更改,我们不想显示警报 (this.showAlertMessage = false),如果表单确实发生了更改,我们希望显示警告 (this.showAlertMessage = true )


旧答案

经过几个小时的努力,我找到了解决方案。

我不得不面对的一个问题是 ionViewWillLeavealert 关闭时也会执行,这使事情变得更加复杂(当 view 即将被关闭时因为您按下后退按钮而关闭,alert 出现,但是当您单击 ok 时,会再次触发事件并再次打开 alert,依此类推...).

要记住的另一件事是 ActionSheetsAlerts 被添加到 navigation stack,所以 this.nav.pop() 不是从堆栈中删除当前视图,删除 alert(因此我们可能会觉得它不能正常工作)。

也就是说,我找到的解决方案是:

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


  }

所以:

  • 我使用一个 confirmedExit 变量来知道你是否已经点击了确定按钮(所以你确认你想要退出页面,并且我知道下一次 ionViewWillLeave 事件被解雇了,我不必显示 alert)
  • exitPage 方法中,首先我执行 this.nav.remove() 从堆栈中删除 alert,完成后,我们执行 this.nav.pop() 返回到上一页。

公认的解决方案在 RC3 中不起作用,这是一个使用 Nav Controller 的 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();
  })
}

如果您在导航控制器上使用 push() 进行导航,您还需要捕获它,否则它会抛出未处理的错误:

this.navCtrl.push(SomePage).catch(() => {});

这是我的 Bostjan 答案版本,没有抛出未处理的异常。

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