La propiedad $ routeProvider resolve permite retrasar el cambio de ruta hasta que se carguen los datos.
Primero defina una ruta con un resolve
atributo como este.
angular.module('phonecat', ['phonecatFilters', 'phonecatServices', 'phonecatDirectives']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/phones', {
templateUrl: 'partials/phone-list.html',
controller: PhoneListCtrl,
resolve: PhoneListCtrl.resolve}).
when('/phones/:phoneId', {
templateUrl: 'partials/phone-detail.html',
controller: PhoneDetailCtrl,
resolve: PhoneDetailCtrl.resolve}).
otherwise({redirectTo: '/phones'});
}]);
observe que la resolve
propiedad se define en la ruta.
function PhoneListCtrl($scope, phones) {
$scope.phones = phones;
$scope.orderProp = 'age';
}
PhoneListCtrl.resolve = {
phones: function(Phone, $q) {
// see: https://groups.google.com/forum/?fromgroups=#!topic/angular/DGf7yyD4Oc4
var deferred = $q.defer();
Phone.query(function(successData) {
deferred.resolve(successData);
}, function(errorData) {
deferred.reject(); // you could optionally pass error data here
});
return deferred.promise;
},
delay: function($q, $defer) {
var delay = $q.defer();
$defer(delay.resolve, 1000);
return delay.promise;
}
}
Observe que la definición del controlador contiene un objeto de resolución que declara cosas que deberían estar disponibles para el constructor del controlador. Aquí phones
se inyecta en el controlador y se define en la resolve
propiedad.
La resolve.phones
función es responsable de devolver una promesa. Se recopilan todas las promesas y el cambio de ruta se retrasa hasta que se resuelvan todas las promesas.
Demostración de trabajo: http://mhevery.github.com/angular-phonecat/app/#/phones
Fuente: https://github.com/mhevery/angular-phonecat/commit/ba33d3ec2d01b70eb5d3d531619bf90153496831
angular.controller()
las definiciones de controlador de tipo? En el$routeProvider
asunto, pensé que tenías que usar los nombres de cadena de los controladores.angular.controller()
, puede asignar el resultado de esta función a una variable (var MyCtrl = angular.controller(...)
) y luego trabajar con eso más (MyCtrl.loadData = function(){..}
). Mira el video de egghead, el código se muestra allí de inmediato: egghead.io/video/0uvAseNXDr0Aquí hay un ejemplo de trabajo mínimo que funciona para Angular 1.0.2
Modelo:
JavaScript:
http://jsfiddle.net/dTJ9N/3/
Versión simplificada:
Como $ http () ya devuelve una promesa (también conocida como diferida), en realidad no necesitamos crear la nuestra. Entonces podemos simplificar MyCtrl. resolver:
El resultado de $ http () contiene datos , estado , encabezados y objetos de configuración , por lo que debemos cambiar el cuerpo de MyCtrl a:
http://jsfiddle.net/dTJ9N/5/
fuente
Unknown provider: datasetsProvider <- datasets
function($http) { return $http({method: 'GET', url: '/someUrl'}) .then( function(data){ return data;}, function(reason){return 'error value';} ); }
Veo a algunas personas preguntando cómo hacer esto usando el método angular.controller con inyección de dependencia amigable con la minificación. Desde que empecé a trabajar, me sentí obligado a volver y ayudar. Aquí está mi solución (adoptada de la pregunta original y la respuesta de Misko):
Dado que este código se deriva de la pregunta / respuesta más popular, no se ha probado, pero debería enviarlo en la dirección correcta si ya comprende cómo hacer un código angular amigable para la minificación. La única parte que mi propio código no requería era una inyección de "Teléfono" en la función de resolución para "teléfonos", ni utilicé ningún objeto de "retraso".
También recomiendo este video de YouTube http://www.youtube.com/watch?v=P6KITGRQujQ&list=UUKW92i7iQFuNILqQOUOCrFw&index=4&feature=plcp , que me ayudó bastante
Si le interesa, he decidido pegar también mi propio código (escrito en coffeescript) para que pueda ver cómo lo hice funcionar.
Para su información, de antemano uso un controlador genérico que me ayuda a hacer CRUD en varios modelos:
fuente
resolve
función en el controlador, en versiones recientes de Angular? Entonces, ¿tiene que declararse justo en la configuración como está aquí?$defer
servicio indefinido , tenga en cuenta que en la versión 1.5.7 de AngularJS, desea utilizar$timeout
en su lugar.Este commit , que es parte de la versión 1.1.5 y superior, expone el
$promise
objeto de$resource
. Las versiones de ngResource que incluyen este commit permiten resolver recursos como este:$ routeProvider
controlador
fuente
GET '/api/1/apps/:appId'
->App.get({id: $routeParams.appId}).$promise();
No puedo usar así$route
a su resolución y uso$route.current.params
. Tenga cuidado,$routeParams
todavía está apuntando a la ruta anterior.Este fragmento es apto para inyección de dependencias (incluso lo uso en combinación de ngmin y uglify ) y es una solución basada en dominio más elegante .
El siguiente ejemplo registra un recurso de teléfono y una ruta de teléfono constante , que contiene toda su información de enrutamiento para ese dominio (de teléfono). Algo que no me gustó en la respuesta proporcionada fue la ubicación de la lógica de resolución : el módulo principal no debe saber nada ni preocuparse por la forma en que los argumentos de los recursos se proporcionan al controlador. De esta manera, la lógica permanece en el mismo dominio.
Nota: si está usando ngmin (y si no lo está: debería) solo tiene que escribir las funciones de resolución con la convención de matriz DI.
La siguiente pieza es inyectar los datos de enrutamiento cuando el módulo está en el estado de configuración y aplicarlo al $ routeProvider .
Probar la configuración de ruta con esta configuración también es bastante fácil:
Puedes verlo en toda su gloria en mi último (próximo) experimento . Aunque este método funciona bien para mí, realmente me pregunto por qué el inyector $ no está retrasando la construcción de nada cuando detecta la inyección de algo que es un objeto prometedor ; haría las cosas muuuucho más fáciles.
Editar: usado Angular v1.2 (rc2)
fuente
I really wonder why the $injector isn't delaying construction of anything when it detects injection of anything that is a promise object
Supongo que omitieron esta funcionalidad porque podría fomentar patrones de diseño que afecten negativamente la capacidad de respuesta de las aplicaciones. La aplicación ideal en su mente es una realmente asíncrona, por lo que la resolución debería ser un caso extremo.Retrasar la visualización de la ruta seguramente conducirá a un enredo asíncrono ... ¿por qué no simplemente rastrear el estado de carga de su entidad principal y usarlo en la vista? Por ejemplo, en su controlador, puede usar las devoluciones de llamada de éxito y error en ngResource:
Luego, en la vista, podrías hacer lo que sea:
fuente
Trabajé desde el código de Misko anterior y esto es lo que he hecho con él. Esta es una solución más actual ya que
$defer
se ha cambiado a$timeout
.$timeout
Sin embargo, la sustitución esperará el período de tiempo de espera (en el código de Misko, 1 segundo), luego devolverá los datos con la esperanza de que se resuelva a tiempo. De esta manera, vuelve lo antes posible.fuente
Usando AngularJS 1.1.5
Actualización de la función 'teléfonos' en la respuesta de Justen usando la sintaxis AngularJS 1.1.5 .
Original:
Actualizado:
Mucho más corto gracias al equipo de Angular y sus colaboradores. :)
Esta es también la respuesta de Maximilian Hoffmann. Al parecer, ese compromiso lo hizo en 1.1.5.
fuente
$promise
en los documentos . Podría haber sido sacado a partir de v2.0 +.Puede usar la propiedad de resolución $ routeProvider para retrasar el cambio de ruta hasta que se carguen los datos.
Tenga en cuenta que la
resolve
propiedad se define en la ruta.EntitiesCtrlResolve
yEntityCtrlResolve
es objetos constantes definidos en el mismo archivo queEntitiesCtrl
yEntityCtrl
controladores.fuente
Me gusta la idea de darkporter porque será fácil para un equipo de desarrollo nuevo en AngularJS entender y trabajar de inmediato.
Creé esta adaptación que usa 2 divs, uno para la barra de carga y otro para el contenido real que se muestra después de cargar los datos. El manejo de errores se haría en otro lugar.
Agregue un indicador 'listo' a $ scope:
En vista html:
Ver también: Documentos de la barra de progreso de Boostrap
fuente
Me gustaron las respuestas anteriores y aprendí mucho de ellas, pero hay algo que falta en la mayoría de las respuestas anteriores.
Estaba atrapado en un escenario similar donde estaba resolviendo la URL con algunos datos que se obtienen en la primera solicitud del servidor. El problema que enfrenté fue qué pasa si la promesa es
rejected
.Estaba usando un proveedor personalizado que solía devolver uno
Promise
que fue resuelto por elresolve
de$routeProvider
en el momento de la fase de configuración.Lo que quiero enfatizar aquí es el concepto de
when
que hace algo como esto.Ve la url en la barra de url y luego el
when
bloque respectivo en el controlador llamado y la vista se refiere hasta ahora muy bien.Digamos que tengo el siguiente código de fase de configuración.
En la URL raíz del navegador, se llama al primer bloque de ejecución; de lo contrario,
otherwise
se llama.Imaginemos que se llama a un escenario en el que golpeé rootUrl en la
AuthServicePrivider.auth()
función de barra de direcciones .Digamos que la promesa devuelta está en estado de rechazo , ¿entonces qué?
Nada se representa en absoluto.
Otherwise
el bloque no se ejecutará como lo es para cualquier url que no esté definida en el bloque de configuración y que sea desconocida para la fase de configuración de angularJs.Tendremos que manejar el evento que se dispara cuando esta promesa no se resuelve. En caso de fallo
$routeChangeErorr
se dispara$rootScope
.Se puede capturar como se muestra en el código a continuación.
En general, es una buena idea poner el código de seguimiento de eventos en el bloque de ejecución de la aplicación. Este código se ejecuta justo después de la fase de configuración de la aplicación.
De esta manera podemos manejar el fracaso de la promesa en el momento de la fase de configuración.
fuente
He tenido una interfaz de panel deslizante multinivel compleja, con capa de pantalla deshabilitada. Crear una directiva sobre la capa de pantalla de desactivación que crearía un evento de clic para ejecutar el estado como
estaban produciendo un efecto de parpadeo. history.back () en lugar de que funcionó bien, sin embargo, no siempre está de vuelta en la historia en mi caso. Entonces, lo que descubrí es que si simplemente creo el atributo href en mi pantalla de desactivación en lugar de state.go, funcionaría de maravilla.
Directiva 'atrás'
app.js acabo de guardar el estado anterior
fuente
Una posible solución podría ser usar la directiva ng-cloak con el elemento donde estamos usando los modelos, por ejemplo
Creo que este requiere menos esfuerzo.
fuente