web-dev-qa-db-fra.com

Comment détecter un événement de clic sur le bouton Précédent du navigateur en utilisant angular

Est-il possible de détecter qu'un utilisateur a saisi une page en utilisant le bouton d'historique dans son navigateur? De préférence, je veux détecter cette action en utilisant angular.js.

Je ne veux pas utiliser le routage angulaire. Cela devrait également fonctionner si un utilisateur envoie un formulaire et après une soumission réussie au serveur et une redirection, cela devrait également être possible si l'utilisateur revient au formulaire en utilisant le bouton Précédent du navigateur.

74
Thomas Kremmel

Voici une solution avec Angular. 

myApp.run(function($rootScope, $route, $location){
   //Bind the `$locationChangeSuccess` event on the rootScope, so that we dont need to 
   //bind in induvidual controllers.

   $rootScope.$on('$locationChangeSuccess', function() {
        $rootScope.actualLocation = $location.path();
    });        

   $rootScope.$watch(function () {return $location.path()}, function (newLocation, oldLocation) {
        if($rootScope.actualLocation === newLocation) {
            alert('Why did you use history back?');
        }
    });
});

J'utilise un bloc d'exécution pour lancer ceci. D'abord, je stocke l'emplacement actuel dans $ rootScope.actualLocation, puis j'écoute $ locationChangeSuccess et, le cas échéant, je mets à jour actualLocation avec la nouvelle valeur.

Dans $ rootScope, je surveille les changements dans le chemin de l'emplacement et si le nouvel emplacement est égal à previousLocation, c'est que $ locationChangeSuccess n'a pas été déclenché, ce qui signifie que l'utilisateur a utilisé l'historique en arrière.

114
Bema

Si vous souhaitez une solution plus précise (détection en amont et en aval), j'ai étendu la solution fournie par Bertrand :

$rootScope.$on('$locationChangeSuccess', function() {
    $rootScope.actualLocation = $location.path();
});


$rootScope.$watch(function () {return $location.path()}, function (newLocation, oldLocation) {

    //true only for onPopState
    if($rootScope.actualLocation === newLocation) {

        var back,
            historyState = $window.history.state;

        back = !!(historyState && historyState.position <= $rootScope.stackPosition);

        if (back) {
            //back button
            $rootScope.stackPosition--;
        } else {
            //forward button
            $rootScope.stackPosition++;
        }

    } else {
        //normal-way change of page (via link click)

        if ($route.current) {

            $window.history.replaceState({
                position: $rootScope.stackPosition
            });

            $rootScope.stackPosition++;

        }

    }

 });
11
Mariusz Karpicki

Pour le routage, j'utilise le code ci-dessous.

Dans App.run(), utilisez

 $rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams) 
 {

    if (toState.name === $rootScope.previousState )
       { 
          // u can any 1 or all of below 3 statements
         event.preventDefault();  // to Disable the event
         $state.go('someDefaultState'); //As some popular banking sites are using 
         alert("Back button Clicked");

       }
 else
      $rootScope.previousState= fromState.name;
   });

Vous pouvez obtenir la valeur 'previousState' dans l'événement '$ stateChangeSuccess' également comme suit si vous le souhaitez.

    $rootScope.$on("$stateChangeSuccess", function (event, toState, toParams, fromState, fromParams) 
   {

        $rootScope.previousStatus = fromState.name;
    });
8
harish polanki

Je sais que c'est une vieille question. Quoi qu'il en soit :) 

La réponse de Bema est superbe. Cependant, si vous voulez le faire fonctionner avec des URL "normales" (sans hachage je suppose), vous pouvez comparer le chemin absolu au lieu de celui renvoyé par $location.path():

myApp.run(function($rootScope, $route, $location){
//Bind the `$locationChangeSuccess` event on the rootScope, so that we dont need to 
//bind in induvidual controllers.

    $rootScope.$on('$locationChangeSuccess', function() {
        $rootScope.actualLocation = $location.absUrl();
    });      

    $rootScope.$watch(function () {return $location.absUrl()}, function (newLocation, oldLocation) {
        if($rootScope.actualLocation === newLocation) {
            alert('Why did you use history back?');
        }
    });
});
1
Jahongir Rahmonov

Donc, j'ai transcrit la réponse de @Bema en TypeScript, et voici à quoi ça ressemble:

namespace MyAwesomeApp {
    // ReSharper disable once Class
    function detectBackButton(
        $rootScope: ng.IRootScopeService,
        $location: ng.ILocationService
    ) {
        let actualLocation: string = '';

        $rootScope.$on('$locationChangeSuccess',
            () => {
                actualLocation = $location.path();
            });

        $rootScope.$watch(() => $location.path(),
            (newLocation: string, oldLocation: string) => {
                if (actualLocation === newLocation) {
                    //$rootScope.$broadcast('onBackButtonPressed', null);
                }
            });
    }

    detectBackButton.$inject = [
        '$rootScope',
        '$location'
    ];

    angular
        .module('app')
        .run(detectBackButton);
}

Nous n'avons pas besoin de créer une propriété à partir du service $rootScope, nous pouvons simplement avoir notre code «succès de changement sur site» et «code sur site modifié» fermés tous deux sur la variable locale actualLocation. À partir de là, vous pouvez faire ce que vous voulez, comme dans le code d'origine. Pour ma part, j’envisagerais de diffuser un événement afin que les contrôleurs individuels puissent faire tout ce qu’ils doivent, mais vous pouvez inclure des actions globales si vous deviez .

Merci pour cette excellente réponse et j'espère que cela aidera d'autres utilisateurs de TypeScript.

0
Andrew Gray

JavaScript a un objet d'histoire natif.

window.history

Vérifiez le MDN pour plus d'informations. https://developer.mozilla.org/en-US/docs/DOM/window.history?redirectlocale=en-US&redirectslug=window.history

Vous ne savez pas à quel point il est bon de prendre en charge plusieurs navigateurs.

Mettre à jour

Ce que j'ai appelé ci-dessus ne concerne que les navigateurs de type Gecko.

Pour les autres navigateurs, essayez d'utiliser history.js; https://github.com/browserstate/history.js

0
user1467267