Paso 7: Elegir un método de persistencia y aplicarlo


Angular es un framework del lado del cliente, lo que significa que no le interesa lo que tengas implementado en el backend. Por esa razón fue que creé el servicio ToDo en el artículo anterior.

Ahora podré crear las versiones que quiera de ese servicio con el método de persistencia de datos que desee. Podré hacer peticiones a servidores Backend sin interesarme la tecnología donde fueron construidos.

Para llevar a cabo el Paso 7 tendré en cuenta los siguientes métodos de persistencia (que trataré en artículos separados):

  1. LocalStorage: Almacenamiento en el navegador.
  2. Firebase: Almacenamiento en la nube (sincronización en tiempo real).

¿Por qué no utilizar como Backend un framework como Symfony, Laravel, Phalcon o NodeJS con Express? Pregunta usted.

Perfectamente los puedes utilizar, pero es fácil, todo se reduce a hacer peticiones AJAX con el servicio $http a las rutas de los controladores con sus acciones. Si lo has hecho ya con jQuery, te será más fácil con el servicio $http de Angular.

Localstorage

La mayoría de las aplicaciones utilizan este tipo de almacenamiento para cachear información, como las credenciales de un usuario o información sobre su perfil, o bien para guardar toda la información que se genera en la app, como es el caso de las apps ToDo.

Este tipo de apps, como es el caso también de muchos juegos, no necesitan compartir la información que generas con otros, como las tareas que tienes por hacer, o tu marcador personal en el caso de los juegos, por lo que se hace a Localstorage como el almacenamiento perfecto.

Instalando Angular-Local-Storage

Podríamos utilizar la API nativa de HTML5 para localStorage, la cual no es para nada dífícil, pero prefiero aprendas la existencia de este módulo de Angular llamado angular-local-storage:

bower install angular-local-storage --save

La opción --save garantiza que se registre este módulo como una dependencia más del proyecto en el fichero bower.json.

Añade además en el fichero app.js el módulo como una dependencia de la aplicación:

angular
  .module('todosApp', [
    'ngAnimate',
    'ngRoute',
    'ngTouch',
    'LocalStorageModule'
  ])

LocalStorageModule es el nombre de esta dependencia, y no angular-local-storage, pues aunque el fichero se llama de esta forma, el módulo no. Para saber cómo se llama el módulo debes abrir el fichero y ver su declaración, pues no siempre coincide con el nombre del fichero.

Este módulo también expone un servicio que podemos inyectar en cualquier parte de la app: localStorageService, el cual es completamente configurable.

Configurando el servicio

Al guardar un dato en el local storage, normalmente se hace un stringify de los objetos JSON que queremos almacenar. Cuando hay varias apps que utilizan este medio de almacenamiento, es buena práctica que los datos que se guardan tengan un prefijo, para así identificar qué dato pertenece a qué app.

Por ejemplo, si tenemos un dato con clave (key) todos guardado, no sabemos decir qué app fue quien lo creó:

todos : [{name:'Do something', done: false}]

En cambio, si configuro mi app con el prefijo uci, el dato se verá de esta forma:

uci.todos : [{name:'Do something', done: false}]

evitando así que otras apps que no tengan prefijo sobreescriban mi variable todos. El siguiente snippet le asigna dicho prefijo a la aplicación:

angular
  .module('todosApp', [
    'ngAnimate',
    'ngRoute',
    'ngTouch',
    'LocalStorageModule'
  ])

  .config('localStorageServiceProvider', function(localStorageServiceProvider){
  localStorageServiceProvider.setPrefix('uci');
  })

Utilizando el servicio

Con esto puedes comenzar a reelaborar el servicio ToDo, todo lo que hay que hacer es inyectarlo y usarlo (¿recuerdas cuando te comenté que un servicio puede hacer uso de otros servicios?) :

angular.module('todosApp')
.factory('Todo', function (localStorageService) {
  ...
});

Bien, ahora lo que debes hacer es cambiar la creación de la variable privada todos (que tiene información estática) con el siguiente snippet:

var todos = localStorageService.get('todos') || [];

Estoy diciendo aquí que a la variable todos se le asigna lo que está en el local storage, o bien un arreglo vacío si no hay nada almacenado. Con esto aseguro que cada vez que se instancie la app, se busque de forma automática lo que está almacenado y se muestre en la vista instantáneamente.

Las funciones de inserción, eliminación y actualización de este servicio, lo que hacen es modificar la variable anterior, por lo que debemos decir que cada vez que esta variable se modifique, se sincronice con el local storage.

Esto lo logro creando una pequeña función, la cual llamaré justo después de aplicar cualquiera de las operaciones anteriores:

var sync = function (){
    localStorageService.add('todos', todos);
};

Por tanto, la función insertar se debe modificar para que quede de esta forma:

insertTodo : function(todo){
    todos.push(todo);
    sync();
},

Al hacer esto para las demás operaciones garantizas que siempre se mantenga en el local storage la última versión de la lista todos.

Verificando la persistencia

Dirígete ahora a http://localhost:9000 y observa cómo al guardar varios ToDos y recargar la página, estos se mantienen junto con su estado.

Si estás en Chrome/Chromium, ve a la Web Developer Tools (Control + Shift + I) en la pestaña Resources y observa que se creó una variable con key “uci.todos” y de valor la lista de todos que creamos.

localStorage

Conclusiones

¿Pretty cool ha? Lo malo de este método es que si abres la app con otro navegador, no podrás ver tus toDos.

¿No sería genial que mis toDos los pueda ver desde cualquier navegador y, que cuando añada uno nuevo, la acción se realice también en los otros lugares donde esta está abierta, y todos los cambios se manifiesten en tiempo real? ¿Es posible?

: FIREBASE.