versiones varios rutas mvc framework example ejemplo controladores controller reload routes angularjs persist

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:

  1. Antes que nada (ya lo sabe), agregue reloadOnSearch: false a su $routeProvider :

    $routeProvider.when(''/somewhere'', { controller: ''SomeCtrl'', reloadOnSearch: false })

  2. Cambie su etiqueta de anclaje href o ng-href a href="#/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 .

  3. Escuchar el evento en el alcance:

    $scope.$on("$routeUpdate", function(event, route) { // some code here });

  4. Si desea cambiar los parámetros de búsqueda en el código, puede usar el método $location.search() . $ location.search API .



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.