Cómo implementar history.back () en angular.js

190

Tengo una directiva que es el encabezado del sitio con el botón Atrás y quiero hacer clic para volver a la página anterior. ¿Cómo lo hago de forma angular?

Yo he tratado:

<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>

y esta es la directiva js:

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

pero nada pasa. Miré en la API angular.js sobre $ location pero no encontré nada sobre el botón Atrás o history.back().

baba-dev
fuente
1
Mencionaste que esto funcionó para ti. ¿Te lleva a diferentes páginas dentro de tu aplicación o simplemente regresa el navegador? Parece que me devuelve el navegador.
Chookoos
Si ha configurado AngularJS para usar el modo HTML5, ir a cualquier página que ya esté en el historial del navegador usará la versión en caché y no la volverá a cargar. El proyecto en el que estoy trabajando utiliza una mezcla de código antiguo y nuevo, y la página anterior cambia después de que los datos se guardan con AngularJS. No es una opción actualizar la primera página para usar AngularJS, así que tuve que cargar una tercera página, no AngularJS, para redirigirla a la primera. No es una buena solución, pero funciona.
CJ Dennis

Respuestas:

262

Necesita usar una función de enlace en su directiva:

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

Ver jsFiddle .

asgoth
fuente
Pero tengo 2 botones en mi encabezado, uno para inicio y otro para atrás si entiendo su código, el elemento en la función de enlace es el elemento en el que se hizo clic en ese historial de casos. ¿Volver también se aplicará al botón de inicio? )
baba-dev
He cambiado un poco el ejemplo. Ahora hay dos botones (atrás y adelante). Utiliza jQuery ahora, lo que significa que se necesita el alcance. $ Apply () al hacer clic.
asgoth
8
Este código no es comprobable, realmente debería usar el objeto '$ ventana' en lugar de 'ventana'.
Árbitro
¿Funciona esto con IE8? No creo que tenga historia
Neil
55
@Neil, Angular orgullosamente no es compatible con IE8. Entonces no.
Rap
133

Las rutas angulares miran la ubicación del navegador, por lo que simplemente usar window.history.back()al hacer clic en algo funcionaría.

HTML:

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

JS:

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

Generalmente creo una función global llamada '$ back' en el controlador de mi aplicación, que generalmente pongo en la etiqueta del cuerpo.

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

Luego, en cualquier lugar de mi aplicación, puedo hacer <a ng-click="$back()">Back</a>

(Si desea que sea más comprobable, inyecte el servicio $ window en su controlador y úselo $window.history.back()).

Andrew Joslin
fuente
9
Recomiendo no poner nada en una "función global". Hay muchas cosas que le pueden pasar al estado global . En este caso, es principalmente la volatilidad del mismo. El código de un tercero (u otro desarrollador, si está en un equipo grande), por ejemplo, una directiva o un servicio podría modificar fácilmente el $ scope. $ Back para sus hijos. Lo que podría ser difícil de depurar. Definitivamente es una mejor práctica inyectar un servicio en cada componente y exponer la funcionalidad donde sea necesario. El ejemplo es solo "global para la aplicación", pero hay riesgo
Ben Lesh,
Fuente: He tenido cosas que he bloqueado en una aplicación "global" $ scope me muerde demasiadas veces para contarlas, y he dejado de usar esa técnica en favor de los servicios. Que todavía se puede usar, pero es mucho más fácil descubrirlo.
Ben Lesh
65

Idealmente, use una directiva simple para mantener los controladores libres de $ window redundante

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

Usar así:

<button back>Back</button>
Darren
fuente
Me alegra que hayas demostrado la dependencia de $ window, eso es importante.
Chris Smith
20

Otra solución agradable y reutilizable es crear una directiva como esta :

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

entonces úsalo así:

<a href back-button>back</a>
pleerock
fuente
1
Parece funcionar una vez que reordene las curvas de cierre y cambie el nombre de la directiva y el elemento attr para que coincidan entre sí.
remarsh
18

En caso de que sea útil ... Estaba alcanzando las "10 $ digest () iteraciones alcanzadas. ¡Abortando!" error al usar $ window.history.back (); con IE9 (funciona bien en otros navegadores, por supuesto).

Lo puse a trabajar usando:

setTimeout(function() {
  $window.history.back();
},100);
Rob Bygrave
fuente
Otras respuestas hacen uso de simple window. Parece que estás usando el $windowservicio Angular. Tal vez esta es la causa raíz?
superjos
77
Recibí el mismo error en IE9 y esto resolvió el problema. Ver github.com/angular/angular.js/issues/1417 Tiene razón sobre el uso de $ window, todas las demás respuestas son "incorrectas" en este punto, ver docs.angularjs.org/api/ng.$window
tanguy_k
¿Alguna idea de por qué 100ms? Eso es un gran retraso, ¿funciona con menos?
Kevin
@Kevin The 100ms fue solo una duración que pensé que era razonable y no se notaba. De hecho, un retraso menor podría funcionar.
Rob Bygrave
Tengo problemas similares en el último Chrome cuando uso la navegación predeterminada angular en mi aplicación, y el retraso tampoco ayudará. Solo la desactivación de la gestión de navegación de Angular ayudó.
Domi
3

O simplemente puedes usar codigo:

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

Me gusta:

<a class="back" ng-class="icons">
   <img src="../media/icons/right_circular.png" onClick="javascript:history.go(-1);" />
</a>
Arvind Kushwaha
fuente
1
esto se ve mal en muchos niveles, cf. esta publicación de blog de hace casi 10 años
Rocco
1

Hubo un error de sintaxis. Prueba esto y debería funcionar:

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

Angular 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
fuente
0

Para mí, mi problema era que necesitaba navegar hacia atrás y luego hacer la transición a otro estado. Por lo tanto, el uso $window.history.back()no funcionó porque, por alguna razón, la transición ocurrió antes de que ocurriera history.back (), así que tuve que ajustar mi transición en una función de tiempo de espera así.

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

Esto solucionó mi problema.

deb2fast
fuente
0

En AngularJS2 encontré una nueva forma, tal vez sea lo mismo, pero en esta nueva versión:

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

(...)

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

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

Después de mi función, puedo ver que mi aplicación va a la ubicación de uso de la página anterior desde angular2 / router.

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

Paul Leclerc
fuente
Funciona, debe importarlo desde @ angular / común, no @ angular / enrutador.
plexo