Comment implémenter history.back () dans angular.js

191

J'ai une directive qui est un en-tête de site avec un bouton de retour et je veux en cliquant sur pour revenir à la page précédente. Comment le faire de manière angulaire?

J'ai essayé:

<header class="title">
<a class="back" ng-class="icons"><img src="../media/icons/right_circular.png" ng-click="history.back()" /></a>
<h1>{{title}}</h1>
<a href="/home" class="home" ng-class="icons"><img src="../media/icons/53-house.png" /></a>   
</header>

et c'est la directive js:

myApp.directive('siteHeader', function () {
    return {
        restrict: 'E',
        templateUrl: 'partials/siteHeader.html',
        scope: {
            title: '@title',
            icons: '@icons'
        }
    };
});

mais rien ne se passe. J'ai regardé dans l'API angular.js à propos de $ location mais je n'ai rien trouvé sur le bouton de retour ou history.back().

baba-dev
la source
1
Vous avez mentionné que cela fonctionnait pour vous. Cela vous amène-t-il à différentes pages de votre application ou le navigateur revient-il simplement? Il semble que le navigateur me revienne.
Chookoos
Si vous avez configuré AngularJS pour utiliser le mode HTML5, accéder à n'importe quelle page déjà dans l'historique du navigateur utilisera la version mise en cache et ne la rechargera pas. Le projet sur lequel je travaille utilise un mélange d'ancien et de nouveau code, et la page précédente change une fois les données enregistrées avec AngularJS. Ce n'est pas une option pour mettre à niveau la première page pour utiliser AngularJS, j'ai donc dû charger une troisième page non AngularJS pour rediriger vers la première. Ce n'est pas une bonne solution, mais cela fonctionne.
CJ Dennis

Réponses:

262

Vous devez utiliser une fonction de lien dans votre directive:

link: function(scope, element, attrs) {
     element.on('click', function() {
         $window.history.back();
     });
 }

Voir jsFiddle .

asgoth
la source
Mais j'ai 2 boutons dans mon en-tête un pour la maison et un pour le dos si je comprends votre code l'élément dans la fonction de lien est l'élément sur lequel on a cliqué dans ce cas history.back s'appliquera également pour le bouton d'accueil? (Ce qui n'est pas bon )
baba-dev
J'ai un peu changé l'exemple. Maintenant, il y a deux boutons (arrière et avant). Il utilise maintenant jQuery, ce qui signifie que la portée. $ Apply () est nécessaire au clic.
asgoth
8
Ce code n'est pas testable, vous devriez vraiment utiliser l'objet '$ window' au lieu de 'window'.
Arbiter
Cela fonctionne-t-il avec IE8? Je ne crois pas qu'il a de l'histoire
Neil
5
@Neil, Angular ne prend fièrement pas en charge IE8. Donc non.
Rap
133

Les itinéraires angulaires surveillent l'emplacement du navigateur, donc simplement en window.history.back()cliquant sur quelque chose fonctionnerait.

HTML:

<div class="nav-header" ng-click="doTheBack()">Reverse!</div>

JS:

$scope.doTheBack = function() {
  window.history.back();
};

Je crée généralement une fonction globale appelée «$ back» sur mon contrôleur d'application, que je place généralement sur la balise body.

angular.module('myApp').controller('AppCtrl', ['$scope', function($scope) {
  $scope.$back = function() { 
    window.history.back();
  };
}]);

Puis n'importe où dans mon application, je peux le faire <a ng-click="$back()">Back</a>

(Si vous voulez qu'il soit plus testable, injectez le service $ window dans votre contrôleur et utilisez $window.history.back()).

Andrew Joslin
la source
9
Je recommande de ne pas mettre quoi que ce soit dans une "fonction globale". Il y a beaucoup de choses qui peuvent arriver à un État mondial . Dans ce cas, c'est surtout la volatilité de celui-ci. Le code d'un tiers (ou d'un autre développeur, si vous faites partie d'une grande équipe), par exemple, une directive ou un service pourrait facilement modifier la portée $. $ Back pour ses enfants. Ce qui pourrait être difficile à déboguer. Il est certainement préférable d'injecter un service dans chaque composant et d'exposer la fonctionnalité si nécessaire. L'exemple n'est que "global à l'application", mais il y a un risque
Ben Lesh
Source: J'ai eu des choses que j'avais coincées dans une application $ scope "globale" qui me mordait trop de fois pour les compter, et j'ai arrêté d'utiliser cette technique en faveur des services. Ce qui peut encore être trompé, mais c'est beaucoup plus facile à comprendre.
Ben Lesh
65

Idéalement, utilisez une directive simple pour garder les contrôleurs libres de $ window redondants

app.directive('back', ['$window', function($window) {
        return {
            restrict: 'A',
            link: function (scope, elem, attrs) {
                elem.bind('click', function () {
                    $window.history.back();
                });
            }
        };
    }]);

Utilisez comme ceci:

<button back>Back</button>
Darren
la source
Heureux que vous ayez montré la dépendance $ window - c'est important.
Chris Smith
20

Une autre solution intéressante et réutilisable consiste à créer une directive comme celle-ci :

app.directive( 'backButton', function() {
    return {
        restrict: 'A',
        link: function( scope, element, attrs ) {
            element.on( 'click', function () {
                history.back();
                scope.$apply();
            } );
        }
    };
} );

alors utilisez-le simplement comme ceci:

<a href back-button>back</a>
pleerock
la source
1
Cela semble fonctionner une fois que vous réorganisez les boucles de fermeture et renommez la directive et l'élément attr pour qu'ils correspondent.
remarsh
18

Au cas où cela serait utile ... J'étais en train de frapper les "itérations de 10 $ digest () atteintes. Abandon!" erreur lors de l'utilisation de $ window.history.back (); avec IE9 (fonctionne bien dans d'autres navigateurs bien sûr).

Je l'ai fait fonctionner en utilisant:

setTimeout(function() {
  $window.history.back();
},100);
Rob Bygrave
la source
D'autres réponses font usage de plaine window. Vous semblez utiliser le $windowservice Angular. C'est peut-être la cause principale?
superjos
7
J'ai eu la même erreur sous IE9 et cela a résolu le problème. Voir github.com/angular/angular.js/issues/1417 Il a raison d'utiliser $ window, toutes les autres réponses sont "fausses" sur ce point, voir docs.angularjs.org/api/ng.$window
tanguy_k
Une idée sur pourquoi 100ms? C'est tout un retard, ça marche avec moins?
Kevin
@Kevin Les 100 ms étaient juste une durée que je pensais raisonnable et non perceptible. En effet, un délai plus petit pourrait fonctionner.
Rob Bygrave
Je rencontre des problèmes similaires dans la dernière version de Chrome lorsque j'utilise la navigation par défaut angulaire dans mon application, et le retard n'aidera pas non plus. Seule la désactivation de la gestion de la navigation d'Angular a aidé.
Domi
3

Ou vous pouvez simplement utiliser code:

onClick="javascript:history.go(-1);"

Comme:

<a class="back" ng-class="icons">
   <img src="../media/icons/right_circular.png" onClick="javascript:history.go(-1);" />
</a>
Arvind Kushwaha
la source
1
cela semble faux à bien des niveaux, cf. ce billet de blog d'il y a presque 10 ans
Rocco
1

Une erreur de syntaxe s'est produite. Essayez ceci et cela devrait fonctionner:

directives.directive('backButton', function(){
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            element.bind('click', function () {
                history.back();
                scope.$apply();
            });
        }
    }
});
Ripan Kumar
la source
1

Angulaire 4:

/* typescript */
import { Location } from '@angular/common';
// ...

@Component({
  // ...
})
export class MyComponent {

  constructor(private location: Location) { } 

  goBack() {
    this.location.back(); // go back to previous location
  }
}
krmld
la source
0

Pour moi, mon problème était que je devais revenir en arrière, puis passer à un autre état. Donc, l'utilisation $window.history.back()n'a pas fonctionné parce que pour une raison quelconque, la transition s'est produite avant que history.back () ne se produise, j'ai donc dû envelopper ma transition dans une fonction de temporisation comme celle-ci.

$window.history.back();
setTimeout(function() {
  $state.transitionTo("tab.jobs"); }, 100);

Cela a résolu mon problème.

deb2fast
la source
0

Dans AngularJS2, j'ai trouvé une nouvelle façon, c'est peut-être la même chose mais dans cette nouvelle version:

import {Router, RouteConfig, ROUTER_DIRECTIVES, Location} from 'angular2/router'; 

(...)

constructor(private _router: Router, private _location: Location) {}

onSubmit() {
    (...)
    self._location.back();
}

Après ma fonction, je peux voir que mon application va à la page précédente en utilisant l'emplacement d'angular2 / router.

https://angular.io/docs/ts/latest/api/common/index/Location-class.html

Paul Leclerc
la source
Cela fonctionne, vous devez l'importer depuis @ angular / common, pas @ angular / router.
plexus