LIBRERIA ANGULAR. PARTE 4,5. PROVEYENDO E INTEGRANDO

< script src=”my own” title=”parte 4,5. proveyendo e integrando” >

Vayamos al grano… ¡PERDOOOÓN 😥 !

Me he tardado demasiado con los posts, con el blog, y con muchas cosas en general, el año se va a acabar y no se respira aire navideño (todavía 🙄 ). Increíble que este año se haya ido volando, han pasado 5 meses desde que escribí el último post de la serie… Pero bueno, basta de chácharas y a lo que vamos, que para eso estoy :mrgreen:

He hecho muchas modificaciones sobre el código fuente, tantas que por poco y hago un nuevo proyecto en el Gato-Pulpo con tantas modificaciones de fondo y algunas de forma. Son tantas modificaciones que no caben en un post, pero ya ustedes se darán cuenta viendo el repo jejeje ^^’ . A manera de hacer el post suficientemente corto, empecemos de una vez con las modificaciones relevantes para este post, las demás irán saliendo paulatinamente.

Antes de empezar

  • Actualicé la versión de Angular.js a la 1.3.20 (la más reciente al momento de escribir este post), también el componente ngRoute (igual la 1.3.20).
  • Actualicé la versión de Dexie.js a la 1.2 (la más reciente al momento de escribir este post).
  • Las modificaciones de estas versiones NO afectan lo que hemos visto en toda la serie.

Una vez dicho lo anterior, ¡hora de empezar!

Proveyendo

El objeto $provide de Angular.js es el objeto más utilizado por todo el framework, ya que es la base (o un wrapper) para definir otros modulos que crean contenido, nuevos patrones de diseño, entre otras funcionalidades. La siguiente tabla resume, en inglés, todo lo que se puede hacer con los providers:

¿Algunos les suenan conocidos?

¿Algunos les suenan conocidos? XD [Cortesía de angularjs.org 🙄 ]

Hay dos maneras de crear un $provider, la primera es la más fácil: usando la sintaxis de angular ($factory, $service, $value, $constant), al respecto de las dos primeras, ya hablamos de ellas en posts anteriores a este tutorial, y respecto a las dos últimas, hay un artículo muy interesante respecto a la forma “correcta” de usar y entender estos providers.

Un $valueProvider (todos los providers terminan en la palabra “Provider”, sean definidos explícitamente o no) es un objeto que almacena un valor modificable de manera global, sin afectar directamente el $rootScope. Mientras que un $constantProvider es un objeto de sólo lectura que tiene la misma característica de estar disponible globalmente.

...
libreria.value('$msg', 'Agregado a la lista!'); //$valueProvider

libreria.constant('DB', new Dexie('libreria-angular')); //$constantProvider
...

La segunda forma de definir un provider:

...
//Provider de tablas para la estructura de la base de datos
libreria.provider('tablas', [function() { //$tablasProvider
	var self = this; // cambio de scope, "this" ahora es local
...

La línea 6 es importante porque cada provider definido explícitamente, debe sobreescribir el método $get del objeto $provide, eso implica que dicho método y todos los demás dentro del provider, van a cambiar de $scope sin que podamos advertirlo, a menos que hagamos la persistencia del $scope local de la función dentro del método. Sin profundizar mucho, acá la implementacion de dicho método (está dentro de un objeto, por eso la sintaxis):

...
	//Método proveedor que registra y revela los métodos del provider
	$get: function() {
		return {
			setCollectionToMap: self.setCollectionToMap(key, name),
			getCollectionFromMap: self.getCollectionFromMap(key),
			setDataToMap: self.setDataToMap(key, data),
			getDataFromMap: self.getDataToMap(key),
			getMap: self.getMap()
		};
	}
...

En una fase de configuración, los providers son sumamente útiles, ya que pueden realizar métodos antes de que incluso, otras instancias del mismo objeto sean utilizadas dentro de la aplicación, dicho en otras palabras, podemos “pre-arrancar” la aplicación y ejecutar otras funciones (como configurar una base de datos, una autenticación, o sincronizar datos con API REST, por ejemplo) antes de iniciar realmente la aplicación como tal. Puedes ver el archivo config.js y darte una idea de lo útil de los providers.

Controlando

Reescribí los controladores para usar directamente el servicio $crud según corresponda. Antes estaba contra un array sin persistencia, ahora está persistida en la base de datos IndexedDB generada con Dexie.js. Adicionalmente, creé un nuevo controlador, que emite un aviso que indica una operación satisfactoria, usando el $valueProvider creado en la fase de configuración.

...
libreria.controller('AvisoCtrl', ['$scope', '$msg', function ($scope, $msg) {
	$scope.mensaje = $msg;
}]);
...

Enrutando

En vez de usar dos templates distintos para la lista de libros seleccionada (inicialmente y vía filtro de categorías), usé el mismo template para ambas rutas, con la salvedad de que el filtro de búsqueda fuera aplicable a ambas de forma transparente.

...
	.when('/categorias/:indice', {
		templateUrl: rootDir+'/libros.html',
		controller: 'LibrosCtrl'
	})
...

Fabricando

Los métodos que realizaban operaciones contra el array de categorías y de libros fueron eliminados de sus respectivos factories, para dejar que los controllers hagan las operaciones de persistencia directa con la base de datos a través del servicio $crud (del cual hablé en un post anterior). No hay mucho más que decir ^^’

Sirviendo

El archivo service.js es el que más modificaciones ha sufrido, empezando porque tuve que aprender a usar la API Q+ de Promises que tiene Angular.js (no es fácil, pero es muy útil XD ), particularmente el llenado inicial de la base de datos es un código bastante complejo si no conoces los conceptos que involucra la programación asíncrona y trabajar con Promises en Javascript:

...
	/* Llenar ambas tablas */
	var P = [
		self.obtenerTodo('listaLibros'),    // [0]
		self.obtenerTodo('listaCategorias') // [1]
	];

	$q.all(P).then(function (data) {
		if (data[0].length == 0) { // LLenar tabla listaLibros
			self.llenar('listaLibros', libreria.listaLibros, libreria.Libro);
		}
		if (data[1].length == 0) { // Llenar tabla listaCategorias
			self.llenar('listaCategorias', catalogo.listaCategorias, catalogo.Categoria);
		}
	});
...

Por mencionar un ejemplo: $q.all() recibe un array de Promises y las ejecuta al tiempo, para sumarlas en una única Promise que contiene un hash de valores que retornan ambas Promises ( o_O )… En fin, puedes consultar la documentación si te parece enredado 😛

Integrando

¡Uf, pero que largo ha quedado! Si has llegado hasta acá, te felicito, he acá los resultados:

Lista de libros traídos desde la base de datos

Lista de libros extraídos desde la base de datos IndexedDB

Obtenemos confirmación al añadir un nuevo libro con el método addLibro()…

Vemos la persistencia reflejada en la base de datos

y vemos la persistencia reflejada en la base de datos!

Añadimos nueva categoría...

Añadimos nueva categoría…

... y vemos el cambio reflejado ^^'

… y nuevamente vemos el cambio reflejado ^^’

Añadimos un nuevo libro de la nueva categoría creada

Añadimos un nuevo libro de la nueva categoría creada

Resultado final de las operaciones sobre la base de datos XD

Resultado final de las operaciones sobre la base de datos XD

Parece que con toda la información que he adquirido, quisiera extender el tutorial jejeje ^^’ , pero por ahora, aplausos para mí que sumo +0,5 a la cuenta.

Gracias por la espera y por la paciencia 😉

</script>

Anuncios

Un comentario en “LIBRERIA ANGULAR. PARTE 4,5. PROVEYENDO E INTEGRANDO

Los comentarios están cerrados.