¿Es posible detectar que un usuario ingresó a una página usando el botón de retroceso del historial en su navegador? Preferiblemente quiero detectar esta acción usando angular.js.
No quiero usar enrutamiento angular. También debería funcionar si un usuario envía un formulario y después de un envío exitoso al servidor y una redirección, también debería ser posible si el usuario vuelve al formulario usando el botón Atrás del navegador.
fuente
$locationChangeSuccess
evento se activa después de la$watch
devolución de llamada. Pero cuando la URL cambia con el botón Atrás / Adelante o lahistory.back()
API, el$locationChangeSuccess
evento se activa antes de la$watch
devolución de llamada. Entonces, cuando el disparo de devolución de llamadaactualLocation
ya es igual anewLocation
. Es cómo angular funciona internamente y esta solución solo usa este comportamiento interno./#/news/?page=2
a/#/news/?page=3
. Para capturarlos también puede usar en$location.absUrl()
lugar de$location.path()
(en ambos lugares donde se usa arriba).Si desea una solución más precisa (detección hacia atrás y hacia adelante), la solución extendida entregada por 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++; } } });
fuente
Para el enrutamiento de interfaz de usuario, estoy usando el siguiente código.
Dentro
App.run()
, usa$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; });
Puede obtener el valor 'previousState' en el evento '$ stateChangeSuccess' también de la siguiente manera si desea.
$rootScope.$on("$stateChangeSuccess", function (event, toState, toParams, fromState, fromParams) { $rootScope.previousStatus = fromState.name; });
fuente
Sé que es una vieja pregunta. De todos modos :)
La respuesta de Bema se ve muy bien. Sin embargo, si desea que funcione con URL 'normales' (sin hash, supongo), puede comparar la ruta absoluta, en lugar de la devuelta por
$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?'); } }); });
fuente
JavaScript tiene un objeto de historial nativo.
window.history
Consulte MDN para obtener más información; https://developer.mozilla.org/en-US/docs/DOM/window.history?redirectlocale=en-US&redirectslug=window.history
Aunque no estoy seguro de qué tan bueno es el soporte para múltiples navegadores.
Actualizar
Parece que lo que he llamado anteriormente es solo para navegadores tipo Gecko.
Para otros navegadores, intente utilizar
history.js
; https://github.com/browserstate/history.jsfuente
Entonces, he transcrito la respuesta de @Bema a TypeScript, y así es como se ve:
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); }
No tenemos que crear una propiedad fuera del
$rootScope
servicio, solo podemos hacer que nuestro código 'cambio exitoso en la ubicación' y 'cambio en la ubicación' se cierren sobre laactualLocation
variable local . A partir de ahí, puede hacer lo que quiera, como en el código original. Por mi parte, consideraría retransmitir un evento para que los controladores individuales puedan hacer lo que sea necesario, pero podría incluir acciones globales si fuera necesario. .Gracias por la gran respuesta, y espero que esto ayude a otros usuarios de mecanografiado.
fuente
Mi solución a este problema es
app.run(function($rootScope, $location) { $rootScope.$on('$locationChangeSuccess', function() { if($rootScope.previousLocation == $location.path()) { console.log("Back Button Pressed"); } $rootScope.previousLocation = $rootScope.actualLocation; $rootScope.actualLocation = $location.path(); }); });
fuente
al presionar el botón Atrás, angular dispara solo el evento $ routeChangeStart , $ locationChangeStart no dispara.
fuente