web-dev-qa-db-fra.com

Comment gérer le bouton de retour sur Ionic 2

Comment gérer l'action du bouton de retour sur Ionic 2?

Je veux pouvoir savoir quoi faire en fonction de la page affichée à l'utilisateur.

Je n’ai pas trouvé de bonne réponse à cette question, mais après un moment, j’ai trouvé un moyen de le faire moi-même. Je vais partager avec vous tous.

Merci

15
Alexandre Justino

Voici comment je l'ai fait:

Dans chaque composant Page, j'ai créé une fonction appelée backButtonAction(), qui exécute un code personnalisé pour chaque page.

Code:

import { Component } from '@angular/core';
import { Platform, NavController, ModalController } from 'ionic-angular';
import { DetailsModal } from './details';

@Component({
    selector: 'page-appointments',
    templateUrl: 'appointments.html'
})
export class AppointmentsPage {
    modal: any;

    constructor(private modalCtrl: ModalController, public navCtrl: NavController, public platform: Platform) {
        // initialize your page here
    }

    backButtonAction(){
        /* checks if modal is open */
        if(this.modal && this.modal.index === 0) {
            /* closes modal */
            this.modal.dismiss();
        } else {
            /* exits the app, since this is the main/first tab */
            this.platform.exitApp();
            // this.navCtrl.setRoot(AnotherPage);  <-- if you wanted to go to another page
        }
    }

    openDetails(appointment){
        this.modal = this.modalCtrl.create(DetailsModal, {appointment: appointment});
        this.modal.present();
    }
}

Et dans le app.component.ts, j’ai utilisé la méthode platform.registerBackButtonAction pour enregistrer un rappel qui sera appelé chaque fois que vous cliquez sur le bouton Précédent. À l'intérieur, je vérifie si la fonction backButtonAction existe dans la page en cours et je l'appelle. Si elle n'existe pas, allez simplement dans l'onglet principal/premier.

Cela pourrait être simplifié s’ils n’avaient pas besoin d’effectuer des actions personnalisées pour chaque page. Vous pouvez simplement faire apparaître ou quitter l'application.

Je l'ai fait de cette façon parce que je devais vérifier si le modal était ouvert sur cette page en particulier.

Code:

  platform.registerBackButtonAction(() => {
    let nav = app.getActiveNav();
    let activeView: ViewController = nav.getActive();

    if(activeView != null){
      if(nav.canGoBack()) {
        nav.pop();
      }else if (typeof activeView.instance.backButtonAction === 'function')
        activeView.instance.backButtonAction();
      else nav.parent.select(0); // goes to the first tab
    }
  });

si la page en cours est le premier onglet, l'application se ferme (comme défini dans la méthode backButtonAction).

29
Alexandre Justino

Ionic Dernière version 3.xx app.component.ts file import { Platform, Nav, Config, ToastController} from 'ionic-angular';

constructor(public toastCtrl: ToastController,public platform: Platform) {
platform.ready().then(() => { 
      //back button handle
      //Registration of Push in Android and Windows Phone
      var lastTimeBackPress=0;
      var timePeriodToExit=2000;

  platform.registerBackButtonAction(() => {
     // get current active page
      let view = this.nav.getActive();
    if(view.component.name=="TabsPage"){
                    //Double check to exit app                  
                    if(new Date().getTime() - lastTimeBackPress < timePeriodToExit){
                         this.platform.exitApp(); //Exit from app
                    }else{
                         let toast = this.toastCtrl.create({
                            message: 'Press back again to exit App?',
                            duration: 3000,
                            position: 'bottom'
                          });
                            toast.present();     
                            lastTimeBackPress=new Date().getTime();
                    }
    }else{
         // go to previous page
              this.nav.pop({});
    }
  });

});

}
7
Mohamed Arshath

J'ai utilisé les réponses ici et d'autres sources pour accomplir ce dont j'avais besoin ... J'ai remarqué que, lorsque vous générez l'application de production (--prod), cette approche ne fonctionne pas, car JS rend les choses plus simples et plus simples:

this.nav.getActive().name == 'PageOne'

A cause de cela, j'utilise ensuite dans l'instruction "if":

view.instance instanceof PageOne

Donc, le code final ressemble à ceci:

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

  //Back button handling
  var lastTimeBackPress = 0;
  var timePeriodToExit = 2000;
  this.platform.registerBackButtonAction(() => {
    // get current active page
    let view = this.nav.getActive();
    if (view.instance instanceof PageOne) {
      if (new Date().getTime() - lastTimeBackPress < timePeriodToExit) {
          this.platform.exitApp(); //Exit from app
      } else {
        let toast = this.toastCtrl.create({
          message: 'Tap Back again to close the application.',
          duration: 2000,
          position: 'bottom',
        });
        toast.present();     
        lastTimeBackPress = new Date().getTime();
      } 
    } else if (view.instance instanceof PageTwo || view.instance instanceof PageThree) {
      this.openPage(this.pages[0]);
    } else {
      this.nav.pop({}); // go to previous page
    }
  });
});
6
airjure

Selon la documentation Ionic 2 RC.4 de ici :

Vous pouvez utiliser la méthode registerBackButtonAction(callback, priority) de l'API Platform pour enregistrer l'action en appuyant sur le bouton Précédent.

L’événement du bouton Précédent est déclenché lorsque l’utilisateur appuie sur le bouton Précédent de la plateforme native, également appelé bouton «matériel». Cet événement est utilisé uniquement dans les applications Cordova exécutées sur les plates-formes Android et Windows. Cet événement n'est pas déclenché sur iOS car iOS ne comporte pas de bouton de retour matériel, comme le fait un appareil Android ou Windows.

L'enregistrement d'une action de bouton de retour matériel et la définition d'une priorité permettent aux applications de contrôler l'action à appeler lorsque le bouton de retour matériel est enfoncé. Cette méthode détermine quelle action du bouton Précédent enregistrée a la priorité la plus élevée et doit être appelée.

Paramètres :

  • callback: fonction à appeler lorsque le bouton de retour est enfoncé, si cette action enregistrée a la priorité la plus haute.
  • priority: numéro permettant de définir la priorité de cette action. Seule la plus haute priorité sera exécutée. Défaut à 0

Retourne: Fonction: fonction qui, lorsqu'elle est appelée, annulera l'enregistrement de l'action du bouton Précédent.

3
Prerak Tiwari

Dans Ionic 3 Lazy Loading, je n’ai jamais ressenti le besoin de gérer le comportement du navigateur lorsque, comme pour platform.is ("cordova"), j’ai créé la méthode suivante qui gère tous les scénarios antérieurs: 

// If a view controller is loaded. Just dismiss it.
let nav = this.app.getActiveNav();
let activePortal = this._ionicApp._loadingPortal.getActive() ||
this._ionicApp._modalPortal.getActive() ||
this._ionicApp._toastPortal.getActive() ||
this._ionicApp._overlayPortal.getActive();
if(activePortal && activePortal.index === 0) {
    /* closes modal */
    activePortal.dismiss();
    return;
}

// If a state is pushed: Pop it.
if (this.nav.canGoBack()) {
  this.nav.pop();
  return;
} else 
// Else If its a tabs page: 
if (this.nav.getActiveChildNav()) {     
    const tabs: Tabs = this.nav.getActiveChildNav();
    const currentTab = tabs.getActiveChildNavs()[0];
    // If any page is pushed inside the current tab: Pop it
    if(currentTab.canGoBack()) {
      currentTab.pop();
      return;
    }
    else 
    // If home tab is not selected then select it.
    if(tabs.getIndex(currentTab) !=0){
      tabs.select(0);
      return;
    }
}
else 
// If a menu is open: close it.
if (this.menu.isOpen()) {
  this.menu.close();
  return;
}




if (this.exitApp) {
  this.platform.exitApp();
  return;
}
this.exitApp = true;

const toast = this.toastCtrl.create({
  message: this.exitMessage || 'press again to exit',
  duration: 4000,
  position: 'bottom',
  cssClass: 'exit-toastr',
});
toast.present();
setTimeout(() => {
  this.exitApp = false;
}, 2000);
0
Arslan Ali

En fait, ionViewWillLeave fonctionne mieux dans mon cas.

 enter image description here

Voici la documentation officielle sur la navigation dans le cycle de vie

0
Alexey Strakh

J'ai trouvé le moyen le plus simple, ajoutez simplement le code suivant dans app.component:

this.platform.registerBackButtonAction((event) => {
    let activePortal = this.ionicApp._loadingPortal.getActive() ||
    this.ionicApp._modalPortal.getActive() ||
    this.ionicApp._toastPortal.getActive() ||
    this.ionicApp._overlayPortal.getActive();
    if(activePortal && activePortal.index === 0) {
        /* closes modal */
        activePortal.dismiss();
    } else {
        if(this.nav.getActive().name == 'Homepage') {    // your homepage
            this.platform.exitApp();
        }
        else {
            if(this.nav.canGoBack())
                this.nav.pop();
            this.nav.setRoot(Homepage);
        }
    }
},101);

C'est tout! Pas besoin d'ajouter de code supplémentaire sur chaque page!

0
Tushar Walzade

J'ai une approche légèrement différente de celle de @amr abdulaziz. J'utilise le setTimeout pour contrôler en arrière ou quitter. J'espère que cela vous donnera une autre option pour implémenter le bouton de retour.

  initBackButtonBehaviour() {
    this.platform.registerBackButtonAction(() => {
      console.log("Back button pressed");
      if (this.readyToExit) {
        this.platform.exitApp();
        return;
      }

      let activePortal = this.ionicApp._loadingPortal.getActive() ||
        this.ionicApp._modalPortal.getActive() ||
        this.ionicApp._toastPortal.getActive() ||
        this.ionicApp._overlayPortal.getActive();

      if (activePortal) {
        activePortal.dismiss();
        activePortal.onDidDismiss(() => { });

        return; // stop any further action after closing any pop up modal or overlay
      }

      if (this.menuCtrl.isOpen()) {
        this.menuCtrl.close();
        return;   // stop any further action after menu closed
      }
      else if (this.nav.canGoBack()) {
        this.nav.pop();
        return;   // stop any further action after navigation pop
      }
      else {
        let activePage = this.nav.getActive().instance;

        let whiteListPages = [HomePage];

        // if current page is not in whitelistPage
        // then back to home or login page first
        if (whiteListPages.indexOf(activePage.constructor) < 0) {
          this.nav.setRoot(HomePage);

          return;
        } else if (whiteListPages.indexOf(activePage.constructor) >= 0) {
          this.utils.showToast('Press back button again to exit', 1500);

          this.readyToExit = true;
          setTimeout(() => {
            this.readyToExit = false;
          }, 1500);

        } else {
          console.error('cannot handle back button');
        }

      }
    }, 101);

0
Kimman wky

Meilleure solution pratique après une longue recherche.

cela fonctionne à 100%, et l'a testé dans un appareil réel 

   this.Platform.registerBackButtonAction(() => {
          // try to dismiss any popup or modal
          console.log("Back button action called");

          let activePortal = this.ionicApp._loadingPortal.getActive() ||
            this.ionicApp._modalPortal.getActive() ||
            this.ionicApp._toastPortal.getActive() ||
            this.ionicApp._overlayPortal.getActive();

          if (activePortal) {
            // ready = false;
            activePortal.dismiss();
            activePortal.onDidDismiss(() => {  });

            console.log("handled with portal");
            return;
          }

          // try to close the menue

          if(this.MenuController.isOpen()){
            this.closeMenu();
            return;
          }
          else if(this.nav.canGoBack()){
            this.nav.pop();
            return;
          }else{

            let activePage = this.nav.getActive().instance;

            let whitelistPages = [LoginPage, HomePage];

            // if current page is not in whitelistPage
            // then back to home or login page first
            if (whitelistPages.indexOf(activePage.constructor) < 0) {
              this.nav.setRoot(this.userLoggedIn ? HomePage : LoginPage);

              return;
            }else if(whitelistPages.indexOf(activePage.constructor) > 0){
              this.AppUtilities.showConfirm("Exit","Are you want to exist the app ? ").subscribe(
                ()=>{
                  this.Platform.exitApp();
                },
                ()=>{}
              )
            }else{
              console.error('cannot handel back button')
            }


          }

        });

0
Amr Ibrahim

Enfin, j’ai trouvé une bonne solution pour la dernière version 3.xx ionique. 

//Check Hardware Back Button Double Tap to Exit And Close Modal On Hardware Back
      let lastTimeBackPress = 0;
      let timePeriodToExit  = 2000;
      this.platform.registerBackButtonAction(() => {
          let activePortal = this.ionicApp._loadingPortal.getActive() || // Close If Any Loader Active
          this.ionicApp._modalPortal.getActive() ||  // Close If Any Modal Active
          this.ionicApp._overlayPortal.getActive(); // Close If Any Overlay Active
          if (activePortal) {
              activePortal.dismiss();
          }
          else if(this.nav.canGoBack()){
            this.nav.pop();
          }else{
              //Double check to exit app
              if (new Date().getTime() - lastTimeBackPress < timePeriodToExit) {
                  this.platform.exitApp(); //Exit from app
              } else {
                this.toast.create("Press back button again to exit");
                lastTimeBackPress = new Date().getTime();
              }
          }            
      });
0
Mohamed Arshath

vous pouvez essayer ces fonctions:

registerBackButton() {
        this.platform.registerBackButtonAction(() => {
            if (this.menu.isOpen()) {
                console.log("Menu is open!", "loggedInMenu");
                this.menu.close();
                console.log("this.menu.isOpen(): " + JSON.stringify(this.menu.isOpen()));
                return;
            }
            console.log("Checking for other pages");

            let checkHomePage = true;
            let max = Globals.navCtrls.length;
            for (let i = 0; i < Globals.navCtrls.length; i++) {
                let n = Globals.navCtrls[i];
                if (n) {
                    if (n.canGoBack()) {
                        console.log("Breaking the loop i: " + JSON.stringify(i));
                        let navParams = n.getActive().getNavParams();
                        if (navParams) {
                            console.log("navParams exists");
                            let resolve = navParams.get("resolve");
                            if (resolve) {
                                n.pop().then(() => resolve({}));
                            } else {
                                n.pop();
                            }
                        } else {
                            n.pop();
                        }
                        checkHomePage = false;
                        return;
                    }
                } else console.log("n was null!");
            }

            if (this.nav.getActive().instance instanceof TabsPage && !this.nav.canGoBack()) {
                let popPageVal = this.backbuttonService.popPage();
                console.log("popPageVal: " + JSON.stringify(popPageVal));
                if (popPageVal >= 0) {
                    console.log("Switching the tab to: ", popPageVal);
                    this.switchTab(popPageVal);
                } else {
                    console.log("Last page is HomePage");

                    if (this.alert) {
                        this.alert.dismiss();
                        this.alert = null;
                    } else {
                        this.showAlert();
                    }
                }
            } else {
                console.log("Last page is not HomePage");
                if (this.nav.canGoBack()) {
                    console.log("We can go back!");
                    this.nav.pop();
                }
            }
        });
    }

    showAlert() {
        this.alert = this.alertController.create({
            title: "Exit?",
            message: "Are you sure you want to exit?",
            buttons: [
                {
                    text: "Cancel",
                    role: "cancel",
                    handler: () => {
                        this.alert = null;
                    }
                },
                {
                    text: "Exit",
                    handler: () => {
                        this.platform.exitApp();
                    }
                }
            ]
        });
        this.alert.present();
    }

    switchTab(tabIndex) {
        if (Globals.tabs && tabIndex >= 0) {
            console.log("Switch condition met");
            Globals.tabIndex = tabIndex;
            Globals.tabs.select(tabIndex);
            Globals.tabs.selectedIndex = tabIndex;
        }
    }

J'espère que cela fonctionne avec vous.

0
Amr AbdelRahman

J'ai pu accomplir cela dans le cas où nous sommes simplement en train de définir des pages racine.

import {Component, ViewChild, Injector} from '@angular/core';
import {Platform, MenuController, Nav, App, IonicApp, NavController} from 'ionic-angular';
import {StatusBar} from '@ionic-native/status-bar';
import {SplashScreen} from '@ionic-native/splash-screen';
import {InvitesPage} from "../pages/invites/invites";
import {RewardsPage} from "../pages/rewards/rewards";
import {ConnectionsPage} from "../pages/connections/connections";
import {MessagesPage} from "../pages/messages/messages";
import {ResourcesPage} from "../pages/resources/resources";
import {SignoutPage} from "../pages/signout/signout";
import {DashboardPage} from "../pages/dashboard/dashboard";
import {AccountPage} from "../pages/account/account";
import {HomePage} from "../pages/home/home";
import {TriviaPage} from "../pages/trivia/trivia";
import {Events} from "ionic-angular/util/events";


@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  @ViewChild(Nav) nav: NavController;
  // make HelloIonicPage the root (or first) page

  public rootPage: any; //if logged in, go to dashboard.
  public pages: Array<{title: string, component: any}>;
  public user: any;
  public routeHistory: Array<any>;

  constructor(public platform: Platform,
              public menu: MenuController,
              public statusBar: StatusBar,
              public splashScreen: SplashScreen,
              private _app: App,
              private _ionicApp: IonicApp,
              private _menu: MenuController,
              protected injector: Injector,
              public _events: Events) {

    this.initializeApp();

    // set our app's pages
    this.pages = [
      {title: 'My Account', component: AccountPage},
      {title: 'Dashboard', component: DashboardPage},
      {title: 'Invites', component: InvitesPage},
      {title: 'Rewards', component: RewardsPage},
      {title: 'Connections', component: ConnectionsPage},
      {title: 'Messages', component: MessagesPage},
      {title: 'Resources', component: ResourcesPage},
      {title: 'Trivia', component: TriviaPage},
      {title: 'Sign Out', component: SignoutPage}

    ];

    this.routeHistory = [];
    this.user = {firstName: ''};

  }

  initializeApp() {

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

      this._setupBrowserBackButtonBehavior();

      let self = this;
      if (sessionStorage.getItem('user')) {
        this.user = JSON.parse(sessionStorage.getItem('user'));
        self.rootPage = TriviaPage;
      } else {
        self.rootPage = HomePage;
      }

      this.routeHistory.Push(self.rootPage);
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
      this.statusBar.styleDefault();
      this.splashScreen.hide();
    });
  }

  openPage(page) {
    // close the menu when clicking a link from the menu
    this.menu.close();
    // navigate to the new page if it is not the current page
    this.nav.setRoot(page.component);
    //store route history
    this.routeHistory.Push(page.component);
  }


  private _setupBrowserBackButtonBehavior() {

    // Register browser back button action(s)
    window.onpopstate = (evt) => {

      // Close menu if open
      if (this._menu.isOpen()) {
        this._menu.close();
        return;
      }

      // Close any active modals or overlays
      let activePortal = this._ionicApp._loadingPortal.getActive() ||
        this._ionicApp._modalPortal.getActive() ||
        this._ionicApp._toastPortal.getActive() ||
        this._ionicApp._overlayPortal.getActive();

      if (activePortal) {
        activePortal.dismiss();
        return;
      }

      if (this.routeHistory.length > 1) {
        this.routeHistory.pop();
        this.nav.setRoot(this.routeHistory[this.routeHistory.length - 1]);
      }


    };

    // Fake browser history on each view enter
    this._app.viewDidEnter.subscribe((app) => {
      if (this.routeHistory.length > 1) {
        history.pushState(null, null, "");
      }

    });

  }
}
0
Judson Terrell