¡Esta es una revisión vieja del documento!
Ya hablamos en Resueltos antes de llamar al controlador sobre la importancia que tenían las promesas en el servicio de rutas. Ahora vamos a explicar esa importancia y volveremos a usar las promesas en paralelo con un objeto.
Lo que vamos a ver es una funcionalidad del método when
de $routeProvider.
Al definir una ruta , en el método when
, le pasamos un objeto con las propiedades templateUrl
y controller
. Este objeto puede tener más propiedades que no vamos a ver excepto la propiedad resolve
. Esta propiedad la podemos ver como el objeto que vimos en promesas en paralelo con un objeto.
El objeto resolve
contiene en cada una de sus propiedades funciones que retornan promesas 1) que se resolverán antes de llamar al controlador y que se pueden acceder desde el controlador si se inyectan en él.
¿Cual es la utilidad de ésto? Para mi son dos:
$scope
del controlador y no aun no está disponible porque el controlador ha hecho una llamada asíncrona 3), no se tienen los datos a tiempo para la directiva.$http
4) o en el resolve
((mediante $route.current.params
).
También en ambos casos se hacen 2 sumas para ver como es usar más de una propiedad en el resolve
.
<!DOCTYPE html> <html ng-app="app"> <head> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js"></script> <script src='//ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular-route.min.js'></script> <script src="//code.angularjs.org/1.2.19/i18n/angular-locale_es-es.js"></script> <script src="script.js"></script> </head> <body> <h1>Esto es el titulo y no cambia</h1> <ul> <li><a href="#/pagina1/2/3/7/9">Ir a la página 1.</a>.Aqui se tardará en mostrar la página pero ya estarán los datos calculados.</li> <li><a href="#/pagina2/2/3/7/9">Ir a la página 2</a>.La página se cargará inmediatamente pero se tardará en calcular los datos</li> </ul> <div ng-view></div> <h3>Esto es un pie y no cambia</h3> </body> </html>
<sxh js;title:script.js> var app = angular.module(“app”, ['ngRoute']);
app.factory(“sumaAsincrona”,['$q','$timeout',function($q,$timeout) {
return function (a,b) { var defered=$q.defer(); var promise=defered.promise; $timeout(function() { try{ var resultado=a+b; defered.resolve(resultado); } catch (e) { defered.reject(e); } },3000); return promise; }
}]);
app.config(['$routeProvider',function($routeProvider) {
$routeProvider.when('/pagina1/:a/:b/:c/:d', { templateUrl: "pagina1.html", controller: "Pagina1Controller", resolve: { suma2y3:['sumaAsincrona','$route',function(sumaAsincrona,$route) { var a=parseInt($route.current.params.a); var b=parseInt($route.current.params.b); return sumaAsincrona(a,b); }], suma7y9:['sumaAsincrona','$route',function(sumaAsincrona,$route) { var c=parseInt($route.current.params.c); var d=parseInt($route.current.params.d); return sumaAsincrona(c,d); }] } }); $routeProvider.when('/pagina2/:a/:b/:c/:d', { templateUrl: "pagina2.html", controller: "Pagina2Controller" }); $routeProvider.otherwise({ redirectTo: '/pagina1/nada' });
}]);
app.controller(“Pagina1Controller”, [“$scope”,”suma2y3”,”suma7y9”,function($scope,suma2y3,suma7y9) {
$scope.mensaje2y3="suma de 2 y 3 es " + suma2y3; $scope.mensaje7y9="suma de 7 y 9 es " + suma7y9;
}]);
app.controller(“Pagina2Controller”, [“$scope”,”$routeParams”,”sumaAsincrona”,function($scope,$routeParams,sumaAsincrona) {
var a=parseInt($routeParams.a); var b=parseInt($routeParams.b); var c=parseInt($routeParams.c); var d=parseInt($routeParams.d); sumaAsincrona(a,b).then(function(resultado){ $scope.mensaje2y3="suma de 2 y 3 es " + resultado; }); sumaAsincrona(c,d).then(function(resultado){ $scope.mensaje7y9="suma de 7 y 9 es " + resultado; });
}]); <sxh>
$http
$http
. Esto queda un poco mal para el usuario ya que ve una página sin datos y un instante después aparecen por arte de mágia los datos.
La solución a estos 2 problemas sería hacer las llamadas asíncronas antes de mostrar la página y no mostrar la página hasta que no se hayan obtenido los datos. Pues bien , eso es justo lo que hace resolve
. No navegará hasta la ruta hasta que no estén todos los datos que necesitamos disponibles.
Veamos ahora un ejemplo de como se usa. como es un poco complejo vamos a ir haciéndolo paso a paso.
===== El servicio sumaAsincrona =====
Lo primero que vamos a hacer es volver a usar la función que creamos para las promesas de sumaAsincrona
, pero vamos a transformarla en un servicio ya que ahora se usará en otro sitio además del controlador.
app.factory("sumaAsincrona",['$q','$timeout',function($q,$timeout) { return function (a,b) { var defered=$q.defer(); var promise=defered.promise; $timeout(function() { try{ var resultado=a+b; defered.resolve(resultado); } catch (e) { defered.reject(e); } },3000); return promise; } }]);Creamos el servicio
sumaAsincrona
que es una función que acepta 2 parámetros. No se deberían tener problemas en entender este código ya que en unidades anterior vimos como crear servicios. En caso de dudas puedes repasar el tema 3.8 factory
===== La ruta con el resolve =====
Ahora vamos a crear una ruta para que haga uso del servicio sumaAsincrona
el cual retorna una promesa.
$routeProvider.when('/pagina1', { templateUrl: "pagina1.html", controller: "Pagina1Controller", resolve: { suma2y3:['sumaAsincrona',function(sumaAsincrona) { return sumaAsincrona(2,3); }] } });
resolve
.resolve
se llama suma2y3
y es una función a la que se le inyecta el servicio de sumaAsincrona
. Posteriormente en el controlador podremos inyectar un servicio llamado suma2y3
que contendrá el resultado de la promesa.sumaAsincrona
.resolve
.resolve
que tiene propiedades cuyos valores son funciones y que esas funciones retornan promesas.
suma2y3
cuyo valor será el resultado de la promesa.
app.controller("Pagina1Controller", ["$scope","suma2y3",function($scope,suma2y3) { $scope.mensaje2y3="suma de 2 y 3 es " + suma2y3; }]);
suma2y3
el cual existe gracias al resolve
de la ruta.$routeParams
pero en el resolve
no es posible usar $routeParams
sino que tenemos que usar $route.current.params
.
Veamos ahora un ejemplo en el que suponemos que los datos a sumar vienen como parámetros de la ruta.
$routeProvider.when('/pagina1/:a/:b', { templateUrl: "pagina1.html", controller: "Pagina1Controller", resolve: { suma2y3:['sumaAsincrona','$route',function(sumaAsincrona,$route) { var a=parseInt($route.current.params.a); var b=parseInt($route.current.params.b); return sumaAsincrona(a,b); }]] } });
a
y b
.$route
para tener acceso al valor de los parámetros.$route.current.params.a
y $route.current.params.b
y los transformamos en un integer ya que son Stringspagina1.html
: Hacemos 2 sumas asíncronas pero calculamos su valor en el resolve
. Esto hace que se tarde 3 segundos desde que se pincha hasta que se muestra la página.pagina2.html
: También hacemos 2 sumas asíncronas pero calculamos su valor en el controlador . Esto hace que la página se muestre inmediatamente tras pinchar pero los datos no se ven hasta pasados 3 segundos.$routeParams