web-dev-qa-db-fra.com

Ionic annule tout le comportement du bouton BACK pour un contrôleur spécifique

Je veux pouvoir remplacer le bouton RETOUR de la barre de navigation et le bouton Matériel.

Je souhaite que cette substitution concerne un contrôleur spécifique, mais pas le reste des contrôleurs.

  • il doit être annulé lorsque l'utilisateur passe à un autre écran

(utilisant ionic v1.0.0 uranium-Unicorn)


Ma raison est que j'ai une liste d'éléments. Un clic sur la liste ouvre une page de détails, avec 3 onglets. Chaque onglet partage le même contrôleur.

Cependant, appuyer sur RETOUR sur l’un de ces onglets doit revenir à la liste principale. C’est ainsi que cela fonctionne sur les appareils natifs, c’est pourquoi j’aimerais que cela fonctionne avec mon application hybride.


De nombreuses solutions proposées en ligne semblent être pour les versions bêta plus anciennes ou pour les enregistrements en dehors des contrôleurs.

Une solution courante pour utiliser le bouton matériel Android dans un contrôleur est la suivante:

$ionicPlatform.registerBackButtonAction(function (event) {
  if($state.current.name=="home"){
    alert("button back");
  }
}, 100);

Toutefois, cela ne semble pas fonctionner avec le bouton de la barre de navigation logicielle, ni avec tous les contrôleurs, pas seulement avec celui-ci.

22
Richard Le Mesurier

Il est possible de remplacer les deux boutons de votre contrôleur, sans aucune modification du code HTML.

Pour résumer:

  • Bouton de la barre de navigation logicielle _ - remplace $rootScope.$ionicGoBack()
  • Bouton Android - utilisez $ionicPlatform.registerBackButtonAction()

Explications détaillées ci-dessous.


La solution pour outrepasser la barre de navigation logicielle du bouton RETOUR vient de comprendre ce que fait Ionic lorsque vous appuyez sur ce bouton. 

Les Ionic docs pour ion-nav-back-button , nous savons déjà que:

le bouton est automatiquement réglé sur $ionicGoBack() lors d’un clic/tapotement.

La recherche du code source dans ionic.bundle.js indique comment cela est déclaré:

$rootScope.$ionicGoBack = function(backCount) {
    $ionicHistory.goBack(backCount);
};

Ignorer cela dans votre propre contrôleur est simple. Assurez-vous de passer $rootScope dans le contrôleur et modifiez simplement le code ci-dessus. Il est judicieux de saisir un pointeur sur la fonction d'origine afin de pouvoir la restaurer si nécessaire ou de l'appeler une fois le traitement personnalisé terminé.

// grab pointer to original function
var oldSoftBack = $rootScope.$ionicGoBack;

// override default behaviour
$rootScope.$ionicGoBack = function() {
    // do something interesting here

    // uncomment below line to call old function when finished
    // oldSoftBack();
};

La solution pour ignorer le bouton BACK du matériel Android, pour un seul contrôleur, provient de la valeur de retour de la fonction registerBackButtonAction(), qui effectue le désenregistrement de la substitution.

Appelez cette méthode de désenregistrement dans le gestionnaire $scope.$on('$destroy'....

var doCustomBack= function() {
    // do something interesting here
};

// registerBackButtonAction() returns a function which can be used to deregister it
var deregisterHardBack= $ionicPlatform.registerBackButtonAction(
    doCustomBack, 101
);

$scope.$on('$destroy', function() {
    deregisterHardBack();
});

Plus de détails ici:


Une solution complète nécessiterait les éléments suivants:

  • remplacer le bouton RETOUR de la barre de navigation logicielle
  • remplacer le bouton de retour dur Android
  • la portée serait un seul contrôleur
  • comportement par défaut restauré

Le code suivant illustre comment cela peut être fait:

// run this function when either hard or soft back button is pressed
var doCustomBack = function() {
    console.log("custom BACK");
};

// override soft back
// framework calls $rootScope.$ionicGoBack when soft back button is pressed
var oldSoftBack = $rootScope.$ionicGoBack;
$rootScope.$ionicGoBack = function() {
    doCustomBack();
};
var deregisterSoftBack = function() {
    $rootScope.$ionicGoBack = oldSoftBack;
};

// override hard back
// registerBackButtonAction() returns a function which can be used to deregister it
var deregisterHardBack = $ionicPlatform.registerBackButtonAction(
    doCustomBack, 101
);

// cancel custom back behaviour
$scope.$on('$destroy', function() {
    deregisterHardBack();
    deregisterSoftBack();
});

Ce problème a été discuté sur les forums ioniques et les pages de problèmes:

61
Richard Le Mesurier

J'ai pris la suggestion de Richard et l'ai mise dans un service pour la rendre plus réutilisable.

Le controlle

angular.module('MainApp').controller('MyController', ['backButtonOverride'], function (backButtonOverride) {
    // override back button for this controller
    backButtonOverride.setup($scope, function() {
        console.log("custom back");
    });
}

Le service

angular.module('MainApp.services', []).factory('backButtonOverride', function ($rootScope, $ionicPlatform) {
    var results = {};

    function _setup($scope, customBackFunction) {
        // override soft back
        // framework calls $rootScope.$ionicGoBack when soft back button is pressed
        var oldSoftBack = $rootScope.$ionicGoBack;
        $rootScope.$ionicGoBack = function() {
            customBackFunction();
        };
        var deregisterSoftBack = function() {
            $rootScope.$ionicGoBack = oldSoftBack;
        };

        // override hard back
        // registerBackButtonAction() returns a function which can be used to deregister it
        var deregisterHardBack = $ionicPlatform.registerBackButtonAction(
            customBackFunction, 101
        );

        // cancel custom back behaviour
        $scope.$on('$destroy', function() {
            deregisterHardBack();
            deregisterSoftBack();
        });
    }

    results.setup = _setup;
    return results;
});
6
oalbrecht

parlez-vous de la navigation souple comme dans le bouton de retour sur la barre d’en-tête ou la barre d’ion? Parce que c'est une solution facile. Créez simplement votre propre barre d’entête personnalisée pour ce modèle. ainsi sur ce modèle d'état juste utiliser quelque chose comme ça.

<div class="bar bar-header bar-positive">
        <button ng-click="someCustomFunction()" class="button button-clear button-light icon-left ion-chevron-left">Go Back</button>
</div>
2
Jess Patton

La réponse ci-dessus pour remplacer $ rootScope. $ IonicGoBack fonctionne partiellement. 

Le problème est avec la manière de deregisterSoftBack. J'ai essayé la $ scope. $ On mentionnée ci-dessus ('$ destroy', une_fonction) ainsi que la nouvelle $ scope. $ On ('$ ionicView.beforeLeave', une_fonction), sans plus. 

La raison: le nouveau contrôleur sera entré avant le deregisterSoftBack afin que le deregister échoue. J'ai donc un peu modifié la solution pour la faire fonctionner.

  1. changer la 

    var oldSoftBack = $rootScope.$ionicGoBack
    

    à 

    $rootScope.oldSoftBack = $rootScope.$ionicGoBack
    
  2. désinscrire dans $ rootScope. $ on ("$ stateChangeStart", votre_fonction), le code est le suivant:

    if ($rootScope.oldSoftBack) {
        $rootScope.$ionicGoBack = $rootScope.oldSoftBack;
        $rootScope.oldSoftBack = null;
    }
    
1
raven.zuo

c'est ma solution :)

Mettez cette partie de code dans votre fonction d'exécution app.js:

//** Go Back interception function ------------------------------------------

    var currentScope;

    var defaultGoBack = $rootScope.$ionicGoBack;

    $rootScope.$ionicGoBack = function() {
        if ( angular.isFunction( currentScope.customGoBack ) ) {

            //assign default go back function to as a "super" function ^^
            currentScope.customGoBack.super = defaultGoBack;

            //if there is a custom back function, execute-it
            currentScope.customGoBack();

        } else {
            //else, execute default go back
            defaultGoBack();
        }
    };

    //Store targetScope to global each time the view is changing
    $rootScope.$on( '$ionicView.beforeEnter', function( event ) {
        currentScope = event.targetScope;
    });

Maintenant, vous pouvez créer une fonction goback personnalisée dans les contrôleurs:

$scope.customGoBack = function() {
   console.log( "customGoBack" );
   $scope.customGoBack.super();
};

Cette fonction sera automatiquement appelée lorsque l'utilisateur appuiera sur le bouton de navigation arrière.

Si vous souhaitez appeler goBack par vous-même, vous pouvez le faire de cette manière:

$rootScope.$ionicGoBack();

Si vous voulez ignorer la fonction personnalisée alors qu'elle est déclarée, vous devez:

$ionicHistory.goBack();

Vous pouvez attribuer un comportement différent au bouton Précédent directement dans chaque contrôleur :)

0
mopi

Nous avons pris les réactions de @ raven.zuo et apporté quelques modifications pour annuler l'enregistrement de l'événement de changement d'état. 

(function () {
    'use strict';

    angular
        .module('appName')
        .service('customBackButtonService', customBackButtonService);

    customBackButtonService.$inject = ['$rootScope', '$ionicPlatform'];
    function customBackButtonService($rootScope, $ionicPlatform) {

        var service = {
            setup: setup
        };

        return service;

        ////////////////

        function setup(customBackFunction) {
            // override soft back
            // framework calls $rootScope.$ionicGoBack when soft back button is pressed
            $rootScope.oldSoftBack = $rootScope.$ionicGoBack;
            $rootScope.$ionicGoBack = function () {
                customBackFunction();
            };
            var deregisterSoftBack = function () {
                $rootScope.$ionicGoBack = $rootScope.oldSoftBack;
            };

            // override hard back
            // registerBackButtonAction() returns a function which can be used to deregister it
            var deregisterHardBack = $ionicPlatform.registerBackButtonAction(
                customBackFunction, 101
            );

            // cancel custom back behaviour
            var backStateChangeWatcher = $rootScope.$on('$stateChangeStart', function () {
                if($rootScope.oldSoftBack){
                    deregisterHardBack();
                    deregisterSoftBack();

                    // Un-register watcher
                    backStateChangeWatcher();
                }
            });
        }
    }
})();

//Called via:

    customBackButtonService.setup(function () {
        console.log('custom back');
    });
0
johnw86