controller - varios - AngularJS: Cambia el hash y la ruta sin cargar completamente el controlador
varios controladores angularjs (10)
Editar
Mejor enfoque al usar ngRoute:
/**
* Add skipReload() to $location service.
*
* See https://github.com/angular/angular.js/issues/1699
*/
app.factory(''location'',
[''$rootScope'', ''$route'', ''$location'',
function($rootScope, $route, $location) {
$location.skipReload = function() {
var lastRoute = $route.current;
var deregister = $rootScope.$on(''$locationChangeSuccess'',
function(e, absUrl, oldUrl) {
console.log(''location.skipReload'', ''absUrl:'', absUrl, ''oldUrl:'', oldUrl);
$route.current = lastRoute;
deregister();
});
return $location;
};
return $location;
}]);
Cómo utilizar:
app.controller(''MyCtrl'', [''$scope'', ''location'', function($scope, location) {
$scope.submit = function() {
location.skipReload().path(path);
};
}]);
Respuesta anterior
He escrito una fábrica reutilizable basada en la respuesta de Jens X Augustsson:
app.factory(''DoNotReloadCurrentTemplate'', [''$route'', function($route) {
return function(scope) {
var lastRoute = $route.current;
scope.$on(''$locationChangeSuccess'', function() {
if (lastRoute.$$route.templateUrl === $route.current.$$route.templateUrl) {
console.log(''DoNotReloadCurrentTemplate'',
$route.current.$$route.templateUrl);
$route.current = lastRoute;
}
});
};
}]);
Funciona con AngularJS 1.0.6
Cómo utilizar:
app.controller(''MyCtrl'',
[''$scope'', ''DoNotReloadCurrentTemplate'',
function($scope, DoNotReloadCurrentTemplate) {
DoNotReloadCurrentTemplate($scope);
}]);
Problema de AngularJS aquí: https://github.com/angular/angular.js/issues/1699
Tengo un controlador, con una ruta como esta:
# / articles / 1234
Quiero cambiar la ruta sin volver a cargar completamente el controlador, así puedo mantener constante la posición de otras cosas en el controlador (enumera ese desplazamiento)
Puedo pensar en algunas formas de hacerlo, pero todas son bastante feas. ¿Hay una mejor práctica para hacer algo como esto? Intenté experimentar con reloadOnSearch: false, pero no parece cambiar nada.
Breve respuesta:
Puedes usar el método $location.search()
como mencionaste. Debería escuchar el evento "$routeUpdate"
en el alcance en lugar de otros eventos de ruta. $ route API .
Explicación:
Antes que nada (ya lo sabe), agregue
reloadOnSearch: false
a su$routeProvider
:$routeProvider.when(''/somewhere'', { controller: ''SomeCtrl'', reloadOnSearch: false })
Cambie su etiqueta de anclaje
href
ong-href
ahref="#/somewhere?param=value"
Esto disparará el evento$routeChangeSuccess
si la parte de la ruta (/somewhere
) no es la misma que la ubicación actual. De lo contrario, activará el evento$routeUpdate
.Escuchar el evento en el alcance:
$scope.$on("$routeUpdate", function(event, route) { // some code here });
Si desea cambiar los parámetros de búsqueda en el código, puede usar el método
$location.search()
. $ location.search API .
Aquí está el complemento: https://github.com/anglibs/angular-location-update
Uso:
$location.update_path(''/notes/1'');
Defina una fábrica para gestionar la ventana de HTML5. History como tal (tenga en cuenta que conservo una pila propia para que funcione también en Android, ya que tiene algunos problemas allí):
.factory(''History'', function($rootScope) {
var StateQueue = [];
var StatePointer = 0;
var State = undefined;
window.onpopstate = function(){
// called when back button is pressed
State = StateQueue.pop();
State = (State)?State:{};
StatePointer = (StatePointer)?StatePointer-1:0;
$rootScope.$broadcast(''historyStateChanged'', State);
window.onpopstate = window.onpopstate;
}
return {
replaceState : function(data, title, url) {
// replace current state
var State = this.state();
State = {state : data};
window.history.replaceState(State,title,url);
StateQueue[StatePointer] = State;
$rootScope.$broadcast(''historyStateChanged'', this.state());
},
pushState : function(data, title, url){
// push state and increase pointer
var State = this.state();
State = {state : data};
window.history.pushState(State,title,url);
StateQueue.push(State);
$rootScope.$broadcast(''historyStateChanged'', this.state());
StatePointer ++;
},
fakePush : function(data, title, url) {
// call this when you do location.url(url)
StateQueue.push((StateQueue.length - 1 >= 0)?StateQueue[StateQueue.length -1]:{});
StatePointer ++;
$rootScope.$broadcast(''historyStateChanged'', this.state());
},
state : function() {
// get current state
return (StateQueue[StatePointer])?StateQueue[StatePointer]:{};
},
popState : function(data) {
// TODO manually popState
},
back : function(data) {
// TODO needed for iphone support since iphone doesnt have a back button
}
}
})
agrega algunos oyentes en tus ámbitos dependientes y estarás bien así:
$scope.$on(''historyStateChanged'', function(e,v) {
if(v)
$scope.state = v;
else
$scope.state = {}
});
así es como lo hago Desde mi punto de vista, la URL solo debería cambiar cuando se carga una nueva vista. Creo que así es como el equipo angular lo pensó de todos modos. Si desea asignar el botón avanzar / retroceder en su modelo, intente hacerlo con la ventana de HTML5. History
Espero poder ayudar. Saludos, Heinrich
Esta solución simple (sorprendentemente) funciona para mí:
$state.params.id = id; //updating the $state.params somehow prevents reloading the state
$location.path(''/articles/'' + id);
Sin embargo, no impide que se vuelva a cargar el estado en los botones Atrás y Adelante. Nota: Estoy usando angularjs 1.2.7 y ui-router 0.0.1 (sé que es antiguo).
Puede hacerlo sin los $locationChange~
HistoryState
$locationChange~
y HistoryState
piratean usando la opción de promesa de resolve
route
.
Suponiendo que tengas una ruta de article
donde cambia ese número, puedes hacer esto;
$routeProvider.when(
''/article/:number'',
{
templateUrl : ''partial.html'',
controller : ''ArticleCtrl'',
resolve : {
load : [''$q'', ''$routeParams'', function($q, $routeParams) {
var defer = $q.defer();
//number was specified in the previous route parameters, means we were already on the article page
if ($routeParams.number)
//so dont reload the view
defer.reject('''');
//otherwise, the number argument was missing, we came to this location from another route, load the view
else
defer.resolve();
return defer.promise;
}]
}
}
);
Si aterrizas aquí en 2015: la verdadera respuesta aquí es no utilizar ninguno de estos hacks (me atrevo a nombrarlos así, porque al usar cualquiera de los métodos enumerados anteriormente perderás la posibilidad de usar resolve y los me gusta), pero para cambiar a ui-enrutador
Aquí hay una presentación práctica sobre las diferencias. La implementación debería ser tan simple como intercambiar $ route por $ state y convertir los estados a nombres.
Actualmente estoy cambiando a un método en el que me referiré con un href a una ruta, con un parámetro get opcional que cambia el estado sin volver a cargarlo. Para más información sobre esto, mira la sección ''params'' aquí
Si configura reloadOnSearch como falso, puede establecer la porción ?a=b&c=d
de la url sin recargar. Sin embargo, no puedes cambiar la ubicación real de manera bonita sin una recarga.
Tenía el mismo desafío,
Encontré un truco en otra respuesta de que hizo el truco
Solución bastante limpia: todo lo que hice fue agregar estas líneas al controlador que establece $ location.path:
var lastRoute = $route.current;
$scope.$on(''$locationChangeSuccess'', function(event) {
$route.current = lastRoute;
});
... y se aseguró de que $ route in se inyectara en el controlador, por supuesto.
Pero aún así, se siente como "DoNotFollowRoutesOnPathChange" es una característica que falta en AngularJS.
/ Jens
Actualización: Como escuchar este evento efectivamente elimina el uso adicional de $ routeProvider configs, tuve que limitar este catch a la ruta actual solamente:
var lastRoute = $route.current;
if ($route.current.$route.templateUrl.indexOf(''mycurrentpath'') > 0) {
$route.current = lastRoute;
}
Poniéndose feo ...
Utilizar:
$routeProvider.when(''/somewhere'', {
controller: ''SomeCtrl'',
reloadOnSearch: false
})
Esto evitará volver a cargar el controlador en el cambio de parámetro de consulta, sino también en el cambio de hash.