2012-09-14 5 views
38

Mi aplicación de una sola página carga una página de inicio y quiero mostrar una serie de ideas. Cada una de las ideas se muestra en un contenedor flash animado, con animaciones que se muestran para alternar entre las ideas.

Las ideas se cargan mediante $ http:

$scope.flash = new FlashInterface scope:$scope,location:$location 

$http.get("/competition.json") 
    .success (data) -> 
    $scope.flash._init data 

Sin embargo, para beneficiarse de la navegación historia y UX que deseen actualizar la barra de direcciones para mostrar la URL correcta para cada idea usando $ ubicación:

$location.path "/i/#{idea.code}" 
$scope.$apply() 

Llamo $ aplica aquí porque este evento proviene del contexto AngularJS, es decir, Flash. Me gustaría que el controlador/vista actual permanezca y que la vista no se vuelva a cargar. Esto es muy malo porque al volver a cargar la vista, el objeto flash completo se descarta y el ciclo del precargador comienza de nuevo.

He intentado escuchar por $ routeChangeStart hacer un preventDefault:

$scope.$on "$routeChangeStart", (ev,next,current) -> 
    ev.preventDefault() 
$scope.$on "$routeChangeSuccess", (ev,current) -> 
    ev.preventDefault() 

pero fue en vano. Todo el asunto sería genial si pudiera encontrar una manera de anular la recarga de la vista cuando cambie $ location.path.

Todavía estoy sintiendo las cosas a mi manera en AngularJS, ¡así que estaría contento de cualquier sugerencia sobre cómo estructurar la aplicación para lograr mi objetivo!

+0

Llegué tarde pero acabo de encontrar un problema similar. ¿Hay alguna razón por la que no pueda poner las 'ideas' fuera de la directiva' ng-view' y darles su propio controlador, que interactúa con los controladores dentro de 'ng-view' a través de la herencia del alcance? Casi siempre estoy preguntando porque así es como resolví mi propio problema y me pregunto si tiene alguna deficiencia, o si debería cambiar a la respuesta aceptada. – jclancy

+1

Si estuviera resolviendo este problema nuevamente hoy, estaría muy tentado de usar el enrutador ui con su capacidad de vista jerárquica. No estoy seguro de que eso resuelva el problema específico de URL que tenía aquí, sin embargo, ¡necesitaría más investigación desde hace un tiempo ...! – chrisbateskeegan

+0

OK, gracias por indicarme en esa dirección, ¡y gracias por responder a un comentario tan tardío! – jclancy

Respuesta

92

En lugar de actualizar la ruta, simplemente actualice query param con un número de página.

establecer su ruta para ignorar los cambios consulta param:

.... 
$routeProvider.when('/foo', {..., reloadOnSearch: false}) 
.... 

y en su actualización de la aplicación $location con:

... 
$location.search('page', pageNumber); 
... 
+10

Gracias por el consejo, Igor. Había detectado y descartado esto antes porque prefería URL como '/ idea/Acas' en lugar de '/ foo? Idea = Acas'. ¡Sin embargo, tiene la virtud de trabajar y en el mundo de los pragmáticos triunfa el trabajo perfecto! – chrisbateskeegan

+5

Perfecto, muchas gracias este consejo. También quiero advertir que si se quiere detectar el cambio de parámetros se puede hacer con:. $ $ ámbito de ("$ routeUpdate", function() {// El parámetro de búsqueda ha cambiado }) – Unitech

+0

¡Esta es la respuesta! Todas estas otras respuestas que encuentro tratan de jugar con $ route y $ state, ¡esto es sencillo y hace el trabajo! –

30

De this blog post:

por defecto, todos los cambios de ubicación pasan por el proceso de enrutamiento, que actualiza la vista angular.

Sin embargo, hay una forma simple de cortocircuitar esto. Relojes angulares para un cambio de ubicación (ya sea que se realice escribiendo en la barra de ubicación , haciendo clic en un enlace o estableciendo la ubicación a través de $location.path()). Cuando detecta este cambio, emite un evento , $locationChangeSuccess, y comienza el proceso de enrutamiento. Lo que hacemos es capturar el evento y restablecer la ruta a lo que era anteriormente.

function MyCtrl($route, $scope) { 
    var lastRoute = $route.current; 
    $scope.$on('$locationChangeSuccess', function(event) { 
     $route.current = lastRoute; 
    }); 
} 
+0

Gracias por esto, suena exactamente como la solución que estaba buscando. He revisado el artículo del blog y tuve una buena jugada. Lamentablemente, no parece funcionar. Intenté colocar el código en '$ routeChangeStart' para ver si eso marcaría la diferencia, pero fue en vano. ¿Hay alguna brujería que me estoy perdiendo? – chrisbateskeegan

+0

Otra idea: intente configurar reloadOnSearch = false, http://docs.angularjs.org/api/ng.$routeProvider Vea también https://github.com/angular/angular.js/pull/1151 –

+2

Este es un terrible, terrible hack ... pero funciona.Y hasta que Angular proporcione una forma de desacoplar el evento de actualización de ubicación de una recarga (lamentablemente, evitar que el valor predeterminado impida que la url cambie por completo) es lo que estamos usando. Y sí, fwiw, reloadOnSearch = false funciona muy bien si lo que necesita cambiar está limitado a los parámetros de búsqueda. Nuestro problema fue con el hash para pestañas de marcadores. – zapnap

1

Usted debe cargar $location a través de la inyección de dependencias y utilizando la siguiente:

$scope.apply(function() { 
    $location.path("yourPath"); 
} 

Tenga en cuenta que debe no uso de hashtags (#) durante el uso de $location.path. Esto es por compatibilidad para el modo HTML5.

+1

Gracias por el consejo. Creo que estoy cargando $ location correctamente 'IndexController = ($ scope, $ http, $ location, $ route) ->' y he actualizado el código de aplicación para que sea como usted sugiere. No estoy exactamente seguro de la diferencia que eso hace, ¿podrías elaborar un poco? – chrisbateskeegan

3

Mi solución fue usar los $ routeChangeStart debido a que proporciona la "próxima "y" últimas "rutas, puede compararlas sin la necesidad de una variable adicional como en $ locationChangeSuccess.

La ventaja es la posibilidad de acceder a los "params" propiedad en ambas "próximos" y "últimos" rutas como next.params.yourproperty cuando se utiliza el estilo URL "/ propiedad/valor" y, por supuesto, utilizar $location.url o $location.path para cambiar la URL en lugar de $location.search() que depende del estilo de URL "? property = value".

En mi caso he utilizado no sólo para eso, sino también para prevenir la ruta para cambiar es el controlador no cambió:

$scope.$on('$routeChangeStart',function(e,next,last){ 
    if(next.$$route.controller === last.$$route.controller){ 
    e.preventDefault(); 
    $route.current = last.$$route; 
    //do whatever you want in here! 
    } 
}); 

En lo personal me siento como AngularJS deben proporcionar una forma de controlarlo, a la derecha ahora suponen que cada vez que cambie la ubicación del navegador, quiere cambiar la ruta.

+1

Esto no funciona para mí cuando intento usar esto dentro de un controlador en AngularJS 1.2.6. Creo que está relacionado con $ routeChangeStart que es una transmisión que no se puede evitar: http://stackoverflow.com/a/14895801/959140 –

0

evento El $ locationChangeSuccess es un poco de un método de fuerza bruta, pero he encontrado que el control de la ruta nos permite evitar cargar la página cuando la trayectoria de la ruta plantilla se modifica, pero vuelve a cargar la página cuando se cambia a una ruta diferente plantilla:

var lastRoute = $route.current; 
$scope.$on('$locationChangeSuccess', function (event) { 
    if (lastRoute.$$route.originalPath === $route.current.$$route.originalPath) { 
     $route.current = lastRoute; 
    } 
}); 

Agregar ese código a un controlador en particular hace que la recarga sea más inteligente.

Editar: Si bien esto hace que sea un poco más fácil, en última instancia, no me gustaba la complejidad del código que estaba escribiendo para mantener la apariencia amigable de las URL. Al final, acabo de cambiar a un parámetro de búsqueda y angular maneja mucho mejor.

0

que tenía que hacer esto, pero después de mimos a tratar de conseguir los $locationChange~ eventos para conseguir que funcione supe que en realidad se puede hacer esto en el route usando resolve.

$routeProvider.when(
    '/page', 
    { 
     templateUrl : 'partial.html', 
     controller : 'PageCtrl', 
     resolve : { 
      load : ['$q', function($q) { 
       var defer = $q.defer(); 

       if (/*you only changed the idea thingo*/) 
        //dont reload the view 
        defer.reject(''); 
       //otherwise, load the view 
       else 
        defer.resolve(); 

       return defer.promise; 
      }] 
     } 
    } 
);