Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta Parte 01


Ya publiqué hace unas semanas mi primera aplicación multiplataforma y con el tiempo y las pruebas que vengo realizando, confirmo cada día que esta combinación es realmente de mucho potencial, por su facilidad y su potencia. Ahora creo que es tiempo de hacer un ejemplo “End to End” que muestre el proceso desde la teoría hasta la ejecución de un app. Así que nada de código para que te bajes, sigue paso a paso y tendrás al final de este post un app en javascript que sincroniza con una base remota y que de yapa puede funcionar en cualquier móvil. “Fasten your seatbelt” y nos vemos al final del Post.

Empecemos definiendo el problema: Tienes tu smartphone super ultra plus y quieres abrir algún App de los miles que tienes instalado y te das cuenta de que se te acabó el saldo y no estas ni siquiera cerca de un Starbucks, o estas en una zona donde la cobertura es recontra mala. Lo que normalmente sucederá es que el App te dirá que no hay red y que no se puede usar. Este escenario parece trivial pero para algunas aplicaciones, es un escenario que tiene que evitarse a toda costa. Llevando el tema más allá, creo que todas las aplicaciones deberían considerar que en algún momento la red se puede caer y deben poder seguir funcionando, al menos en un conjunto básico de funciones. Desde el punto de vista de programación estamos hablando de aplicaciones que soporten trabajar “Off-Line”.

Para hacer todo esto posible hay miles de recetas disponibles y la que presento ahora combina simpleza y potencia. Para ver como debemos comenzar veamos el gráfico:

gen01

Si vamos componente por componente:

  • Servidor: Cloudant es parte de la propuesta Bluemix de la plataforma de servicios cloud de IBM. Está basado en Apache CouchDB con algunas mejoras en el campo de autenticación, manejo de información geográfica y búsquedas. Digamos que es la implementación mas segura y confiable de CouchDB con la gran ventaja de que podemos acceder al nivel gratis del servicio muy fácilmente. De hecho, si generas un tráfico por un total de 50 USD o menos, no pagas y gracias al esquema que les voy a explicar, eso es un montón.
  • Cliente: Ionic Framework es una herramienta para el desarrollo de aplicaciones basadas en HTML 5 con javascript. Está basado en Apache Cordova y permite desarrollar para Android, iOS, Windows Phone 8, Windows 8, y otras mas aunque por ahora solamente Android y iOS son oficialmente soportados. Lo mas importante puede ser que Ionic está basado en AngularJS que es un framework para el desarrollo de aplicaciones JavaScript que facilita el desarrollo de aplicaciones basados en el modelo MVC.
  • Base de datos cliente: PouchDB es un proyecto que trata de implementar CouchDB en javascript. Debido a que el soporte de formatos de base de datos en los móviles es muy variado, PouchDB funciona además como una capa de abstracción de almacenamiento aunque su mayor fortaleza es en la implementación del protocolo de sincronización.

Hay algo que no he dicho aún y es que para los que estamos acostumbrados al mundo SQL significa días difíciles. Personalmente, me parece que el cambio ya se dió al enterarme que el estándar WebSQL, (SQLite para los amigos) ya no es el estándar en muchas de las plataformas móviles. Esto significa que tenemos que empezar a lidiar con NoSQL.

NoSQL significa que ya no hay esquemas o “tablas”, simplemente hay documentos que lo único seguro es que tienen un id único ( aunque por ahí ya vi un caso donde incluso esto no es cierto ). No se engañen, No Tablas no significa No Diseño, al contrario, el diseño tiene que ser mayor con la ventaja de que no hay esquemas que ir impactando. De nuestro diagrama, Cloudant y PouchDB son NoSQL y serán a partir de ahora la columna vertebral de nuestras aplicaciones móviles.

Bien, creo que las explicaciones ya están, ahora lo que queremos ver es una aplicación que nos muestre lo fácil que es entrar al mundo de móviles. Preparemos entonces el entorno.

Organizando las herramientas

Empecemos instalando las herramientas. Primero se debe instalar NodeJS. Es una serie de librerías Javascript que son necesarias para Ionic. En el link podrán encontrar la versión para los sistemas operativos más populares.

Con el NodeJS listo, vamos a instalar ahora Ionic. En una ventana de consola:

c:\>npm install -g ionic

No es requisito pero también deberían instalar Cordova:

c:\>npm install -g cordova

Y listo, Ionic ya está y lo pueden comprobar así:

c:\>ionic info

Ahora, hay que instalar PouchDB, para lo cual necesitamos instalar Bower que es una herramienta para instalar librerías JavaScript. Para eso utilizamos el siguiente comando:

c:\>npm install -g bower

Ahora lo que tenemos que hacer es crear un proyecto Ionic y agregarle las librerías de PouchDB. Para crear un proyecto Ionic, procedemos con el siguiente comando:

c:\>ionic start superdatos

Mediante este comando estamos creando el proyecto llamado “superdatos”. Se ha creado una carpeta con todos los archivos necesarios. Una vez que el comando haya terminado debemos hacer la configuración de SASS que es algo super potente que explicaremos después, por ahora simplemente ejecuten el comando siguiente:

c:\>cd superdatos
c:\superdatos\> ionic setup sass

Para los que entienden CSS, SASS es un CSS con parámetros. Yo todavía no lo entiendo bien, pero lo poco que he hecho es suficiente para darme cuenta de su importancia, así que ahi está. Ahora instalemos PouchDB:

c:\superdatos\>bower install pouchdb

Y listo. Si quieren ver lo que han hecho hasta ahora entonces ejecuten el siguiente comando:

c:\superdatos>ionic serve

Ahora abran un navegador, ingresen el url http://localhost:8100 y listo:

gen07

Así es, sin darse cuenta han hecho una aplicación con una barra de título. Casí nada, pero al menos ya hemos comenzado

Organización de la aplicación

Ahora revisemos todo lo se que ha hecho. Veamos los archivos:

En la carpeta raíz no hay mucho que ver:

gen05

Nos enfocaremos inicialmente en la carpeta www

gen06

  • index.html: es el punto de entrada de nuestra aplicación y donde registramos todas las librerías que queremos usar
  • Carpeta js: es donde colocamos todos los archivos javascript. El principal archivo javascript es app.js que es donde configuramos nuestra aplicación.
  • Carpeta lib: Si ingresan es donde están grabadas todas las librerías que tenemos disponibles para la aplicación. Ionic y PouchDB estarán ahí, además de otras propias de Angular
  • Carpeta img: obvio, las imágenes van aquí.
  • Carpeta css: y aquí van los archivos CSS

Y listo. Ahora nos toca entender por donde comenzar, para lo cual debemos entender el concepto de MVC o Model – View – Controller.

MVC-web-application-development

Según esto, una aplicación se divide en estos tres elementos: modelo, vista y controlador, donde vista es toda la parte gráfica de la aplicación y como el usuario interactúa con ella. El controlador es quien maneja la lógica detrás de las pantallas, cuál es la lógica que se lanza al hacer click en un botón. El modelo es como la lógica del negocio, que también controla lo que grabamos en una base de datos, si al hacer click en un botón que dice grabar, el controlador le tendrá que decir al modelo que tiene grabar una entrada de producto, seguidamente, la vista se refrescará para mostrar todas las entradas de producto. Exacto, el producto es el modelo.

Ya dijimos que Ionic se basa en AngularJS donde es muy fácil identificar al modelo, la vista y el controlador, de hecho sería así:

  • Vista : carpeta templates, archivos HTML o simplemente index.html
  • Controlador: carpeta js, archivos js. Entidad controller en AngularJS
  • Modelo: carpeta js, archivos js. Entidad factory en AngularJS

Es mas simple de lo que parece. Y para eso revisemos nuestra simple aplicación tal cual está ahora. Primero veamos el archivo index.html que tiene definida la vista:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<!-- compiled css output -->
<link href="css/ionic.app.css" rel="stylesheet">
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
</head>
<body ng-app="starter">
<ion-pane>
<ion-header-bar class="bar-stable">


<h1 class="title">Ionic Blank Starter</h1>


</ion-header-bar>
<ion-content>
</ion-content>
</ion-pane>
</body>
</html>

Las líneas que nos interesan por ahora son la 14 y la 16. Primero en la 14 veremos

<script src="js/app.js"></script>

Esta línea le dice a la aplicación que la lógica que necesita está en el archivo app.js que está escrito en javascript como podrán sospechar. Cualquier otra librería tiene que ser declarada aquí para poder ser utilizada. Recuerden esto pues tenemos que regresar aquí mismo para ver que hacemos con PouchDB.

<body ng-app="starter">

Y en la línea 16 le decimos que la aplicación que estamos haciendo es ng-app osea Angular con nombre “starter”.

Ahora revisemos el famoso app.js:

// Ionic Starter App
// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
angular.module('starter', ['ionic'])

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
  });
})

En la línea 5 está definido el módulo ‘starter’ que es el que encontramos en el archivo index.html. Cuando index.html quiera saber que hacer, vendrá a buscar la lógica a este archivo app.js.

Luego en la linea 7 vemos algo importante. Para los que ya tienen experiencia con aplicaciones en Cordova, entenderán la importancia del evento CordovaReady. Para ponerlo simple, Ionic es Cordova en esteroides, así que también hay que esperar por el evento CordovaReady, pero como Ionic habla el dialecto AngularJS entonces tenemos que usar el código tal cual está aquí.

Integrando PouchDB

Pues bien, ya estamos listos para integrar nuestra base de datos así que debemos preguntarnos ¿qué queremos hacer? Pongamos las cosas en el nivel mas simple posible. Digamos que queremos hacer un lector de noticias donde las noticias mas nuevas se muestren al comienzo. Nada complicado. Con esto en la mente, comencemos agregando activando PouchDB en nuestro proyecto, de la siguiente manera. Nuestro archivo index.html debería ser así ahora:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title></title>
    <!-- compiled css output -->
    <link href="css/ionic.app.css" rel="stylesheet">
    <!-- ionic/angularjs js -->
    <script src="lib/ionic/js/ionic.bundle.js"></script>
    <!-- cordova script (this will be a 404 during development) -->
    <script src="cordova.js"></script>
    <!-- your app's js -->
    <script src="js/app.js"></script>
    <script src="lib/pouchdb/dist/pouchdb.js"></script>
  </head>
  <body ng-app="starter">
    <ion-pane>
      <ion-header-bar class="bar-stable">


<h1 class="title">Ionic Blank Starter</h1>


      </ion-header-bar>
      <ion-content>
      </ion-content>
    </ion-pane>
  </body>
</html>

Hemos agregado una línea indicando donde está el archivo con la librería PouchDB. Si se fijan bien, dentro de nuestra carpeta lib está la carpeta con toda la info requerida por PouchDB, aquí simplemente hemos apuntado al archivo de distribución.

NOTA: es una buena idea que tengan una consola abierta solamente para que el comando Ionic serve esté corriendo todo el tiempo ya que Ionic permite que todo lo que hacemos se compile en tiempo real.

En Google Chrome veremos que nuestra app no ha cambiado mucho. Nos toca entonces, crear la base de datos. Para eso, agregamos la siguiente línea en nuestro app.js:

// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
angular.module('starter', ['ionic'])

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
    var db = new PouchDB('news');
  });
})

En la línea 18, creamos la variable que tendrá nuestra base de datos local y le ponemos de nombre ‘news’. Al grabar los cambios, notarán que el navegador se refresca solo y volvemos a ver nuestra app. Parece que todo sigue igual pero no. Para desengañarnos, tenemos que abrir las herramientas (Ctrl + Mayus + I) y vamos a la sección Resources y veremos:

gen08

En recursos, veremos que se ha agregado una base de datos con el nombre _pouch_news y no es coincidencia. Es nuestra base de datos ‘news’ creada por PouchDB en el formato IndexedDB. Todo bien hasta ahora. Ahora veamos como nos conectamos a IBM Bluemix para acceder a Cloudant.

Jugando con Cloudant

En el mundo CouchDB, encontré muchas alternativas “cuasi” gratuitas para comenzar a trabajar pero es lamentable como la falta de visión a largo plazo hace que la confiabilidad no sea algo característico. Todo esto se terminó con Cloudant, ya que IBM es quien está detrás y eso es ya bastante. ¿Porqué no instalar mi propia instancia de CouchDB en mi PC? Simple, Cloudant es gratis hasta 50 USD de tráfico, es super rápido, confiable y otros adjetivos todos muy buenos. Además, estamos en la onda de utilizar herramientas Cloud así que va a tono.

Como siempre, primero hay que crear una cuenta en https://cloudant.com/sign-up/ y ya podrán acceder a esta pantalla:

gen09

Para los fans de CouchDB, esta es una versión algo mejorada de Fauxton con las mejoras que les comenté al inicio. No perdamos mas tiempo y creemos nuestra primera base de datos. Un click en Add new Database, ponemos el nombre ‘news’ por facilidad y listo, veremos esta pantalla ahora:

gen10

Ahora es el momento de reflexionar sobre la estructura de datos que necesitamos. Una noticia tiene un titular, un resumen y el cuerpo, además, tiene una fecha y un autor. Para comenzar, creo que es suficiente, así que agregaremos nuestro primer documento. Hacemos click en el signo mas junto a All Documents  y seleccionamos nuevo documento. Y luego empecemos a crear nuestro documento en formato JSON:

gen12

Simple, ¿Queremos mas campos? no hay problema, le agregas nomas al JSON y listo. ¿Y los índices, llaves primarias, foráneas y otros? Pues no hay, al menos no aquí. Lo único que hay que respetar aquí es que el campo “_id” es obligatorio y debe ser único. ¿Y la clave no es autoincrement? no necesariamente, podemos dejar que se autogenere pero nos perdemos de mucho si hacemos eso. Si se dan cuenta la _id que estoy usando es “news_20150507_vpease_001” que sospechosamente parece ser hecha a propósito y la verdad es que si. Es altamente recomendable utilizar una convención para la creación de claves. En este caso:

  • “news” : indica el tipo de documento. Recuerden que no hay esquemas así que mejor si identificamos así a nuestras entidades.
  • “20150507” : así es, se refiere a la fecha, pues ya dijimos que queremos mostrar las últimas noticias primero.
  • “vpease” : correcto otra vez, es el autor de la noticia.
  • “001” : una pequeña cadena al final para asegurar que el id sea único.

¿Porque todo este lio con la clave? Si bien es cierto que tenemos un campo “tipo” que nos permite diferenciar las entidades entre todos los documentos de la base, CouchDB tiene un método super rápido llamado AllDocs que sólo puede ser ordenado por el campo “_id”. Podemos crear nuevos indices pero ocupan espacio adicional, así que para ahorrarnos algo de espacio y ganar algo de velocidad, NO DEBEMOS AUTOGENERAR LA CLAVE, SIEMPRE DEBEMOS COMPONER LA CLAVE CON CAMPOS DE ORDENACION.

Y finalmente, grabamos y listo.

gen13

Notarán que se ha agregado un campo “_rev”, esto es un mecanismo interno de CouchDB para controlar los cambios y hacer lo que mejor hace: sincronizar.

Podríamos agregar mas noticias, pero por ahora es suficiente. Finalmente tenemos que crear algún tipo de identidad o usuario para poder acceder a los datos. Esta es una de las mejoras de Cloudant, todas las llamadas deben ser autenticadas y el HTTPS viene de gratis. En Cloudant, volvamos a la lista de base de datos:

gen14

Entremos a la sección de permisos ahora:

gen15

Hay dos maneras de dar acceso:

  • Le damos permiso a todos a entrar a los datos
  • Crear un API key/clave

Hay una tercera opción que es la de usar nuestras credenciales administrativas para dar acceso, lo cual es a todas luces incorrecto, como también es incorrecta la opción 1, así que API Keys es la voz. También se puede compartir la base a otro usuario de Cloudant pero eso no es masivo, así que nos quedamos con las API keys. En simple, un API key es un usuario temporal que solamente sirve para acceder a los datos y le podemos asignar permisos. Para mantener todo simple, vamos a darle a esta API key los privilegios de Replicator y Reader.

gen16

Y listo, apunten bien esta combinación de Key y password porque ya no puede volver a generarse. Podrán generar una nueva Key pero ya no podrán recuperar la clave. Fijense que ya le asignamos los privilegios de Reader y Replicator. Ahora, toca finalizar nuestro app cliente.

NOTA CRITICA: Antes de salir hay que activar CORS, así que denle click en Account – CORS y activen All Domains. ¿Qué es CORS? es una protección de los navegadores para no ejecutar código remoto. Para nuestro caso, CORS debe estar siempre activado. La pantalla debe lucir así:

gen18

Agregando la sincronización 

Para esto, debemos entender un tema previamente. La sincronización tiene muchas variantes pero por ahora sólo nos va a importar tres cosas: Dirección, Frecuencia y Eventos.

La dirección se refiere al sentido que tendrán los datos, del Servidor al móvil o del Móvil al Servidor. Dado que solamente vamos a leer, consideraremos la sincronía de Servidor al Móvil.

La frecuencia se refiere a que tan seguido queremos actualizar los cambios. Convenientemente, PouchDB tiene una opción “live” que tratará  de actualizar los datos lo más rápido posible, suena bien pero es mas costosa del lado de Cloudant, así que debemos usarla con mucho cuidado. Igual siempre podemos sincronizar manualmente cuando lo creamos conveniente.

Finalmente, los eventos nos indican como va el proceso. En resumen:

  • change (info) – Generado cada vez que se detecta un nuevo documento escrito.
  • complete (info) – Se genera cuando una sincronización manual termina o cuando se interrumpe una sincronización live.
  • paused (err) – cuando una sincronización live ha terminado y espera por nuevos cambios o cuando se ha interrumpido por algún err.
  • active – cuando una sincronización comienza o cuando se recupera de algún error.
  • denied (err) – cuando las credenciales son rechazadas por el servidor.
  • error (err) – cuando se genera un error irrecuperable como cuando se corta la red.
  • uptodate (deprecated) – Este evento ya esta de salida así que no lo usen

Ahora, como por arte de magia, agregaremos las líneas para activar la sincronización. La magía será en el archivo app.js.

// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
angular.module('starter', ['ionic'])

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
	var key = 'bentareadyessharyinessee';
	var pass = 'OnEixgKgpt8LyEtl0S5DkAon';
	var remote = 'https://'+key+':'+pass+'@supermio.cloudant.com/news';
	var db = new PouchDB('news');
	db.replicate.from(remote,{live:true,retry:true});	
  });
})

Veamos, simplemente hemos agregado unas variables con el API Key y la clave de acceso y el url de la base de datos en Cloudant. Verán que estoy agregando las credenciales al url, sería algo asi: https://user:pass@servidor/basededatos.

En la línea 22 está la línea que hace la verdadera llamada a la sincronización donde hemos indicado un par de parámetros: live y retry que como su nombre lo indica, activarán la replicación “live” y en el caso de algún error, la replicación se intentará nuevamente.

Veamos como se ve la app hasta ahora en Chrome, primero en la consola:

gen17

Si vemos líneas con XHR significa que ya estamos sincronizando. Y para que me crean vamos al tab Resources:

gen20

Y ahí vemos nuestro documento!! Es cierto!

Guardemos ánimo para hacer lo que de veras hace falta que es presentar los datos.

Finalmente, Presentando los datos

Antes de presentar los datos debemos tomar en cuenta los eventos pues recuerden que la base de datos en el móvil comienza vacía y luego irán llegando las noticias debemos poder refrescar la vista. Los eventos ya los vimos así que recordemos que estamos haciendo una replicación “Live” y cuando acabe se generará un evento “paused”, también podríamos usar “change” pero este evento sólo funcionaría para los nuevos cambios. Si por alguna razón, la base remota y la local están iguales, el evento “change” no se generaría, mientras que “paused” si. Primero veamos como va la cosa con “paused”. Para eso agregamos las siguientes líneas a app.js justo después del comando de replicación:

.on('paused',function(info){
		db.allDocs({startkey:'news_\uffff',endkey:'news_',descending: true,include_docs:true})
		.then(function(result){
			$rootScope.$broadcast('refrescar',result.rows);			
		});		
	})

Veamos línea por línea:

  • Línea 23: agregamos un manejador para el evento “paused”. Fijense que el comando db.replicate no tiene el “;” al final, por lo que “.on” es una propiedad del comando “db.replicate”. Luego de la “,” tenemos la función que se ejecutará cuando ocurra el evento.
  • Línea 24: aquí viene el primer choque para los que venimos del mundo SQL. El comando “db.allDocs” es el comando más potente de PouchDB y de hecho de CouchDB también y permite recuperar documentos mediante el índice principal que si se habrán dado cuenta, incluye a todos los documentos en la base de datos. Inicialmente, allDocs recupera todos los documentos, pero toma parámetros para limitar un poco eso. Por ejemplo, aquí le hemos pasado los dos primeros “startkey” y “endkey” que se refieren a algo así como un like y como notarán la cadena que pasamos es “news_” y agregándole el caracter “\uffff” es como ponerle el asterisco, por lo que los dos primeros parámetros significan que debemos traer todos los documentos cuya clave comience con “news_” que gracias a la estructura de claves que fijamos es equivalente a decir que traiga todas las noticias en la base de datos. Seguidamente verán que hemos fijado “descending” a “true” y eso es por la fecha, si recuerdan la estructura de nuestra clave que era “news_fecha_autor_XXX” así que decirle que sea descendente significa que las noticias más recientes estarán al principio, lindo truco. Finalmente, con “include_docs” le decimos que nos traiga todos los datos en el documento, de lo contrario solamente tendremos la clave.
  • Línea 25: Aquí vemos una de las mayores características de aplicaciones NodeJS, Promesas. Dado que db.allDocs se ejecuta de forma asíncrona, no sabemos en que momento ejecutará la siguiente línea, así que con “.then” le decimos que al terminar, ejecute la función incluida.
  • Línea 26: La función que pasamos como promesa ejecuta una sola línea y esta es: “$rootScope.$broadcast” que en simple significa que se enviará un mensaje a todos los contextos indicando que un evento se ha realizado. El evento se llamará “refrescar” y tendrá como parámetros todos los “rows” incluidos en el objeto result, o más simple, todos los documentos recuperados desde la base de datos.

Y listo, hasta ahora hemos trabajado en lo que puede decirse que es el “Controller” de toda la aplicación y como no está asociada a ninguna vista, no podremos crear ninguna lógica que presente los datos. Entonces ahora tenemos que ligar la vista que tenemos ( osea “index.html”) con algún controller.

Primero en la vista “index.html” declaramos el controlador asi:

<body ng-app="starter">
    <ion-pane ng-controller="newsController">
      <ion-header-bar class="bar-stable">


<h1 class="title">Ionic Blank Starter</h1>


      </ion-header-bar>
      <ion-content>
      </ion-content>
    </ion-pane>
  </body>

En la línea 18 verán que hemos agregado la directiva “ng-controller” donde le indicamos a la vista que el controlador es “newsController”. Ahora definamos el controlador en el archivo “app.js”. Pongamos todo el código en el archivo pues los “;” y “.” se vuelven muy importantes:

// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
angular.module('starter', ['ionic'])

.run(function($ionicPlatform,$rootScope) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
	var key = 'bentareadyessharyinessee';
	var pass = 'OnEixgKgpt8LyEtl0S5DkAon';
	var remote = 'https://'+key+':'+pass+'@supermio.cloudant.com/news';
	var db = new PouchDB('news');
	db.replicate.from(remote,{live:true,retry:true})
	.on('paused',function(info){
		db.allDocs({startkey:'news_\uffff',endkey:'news_',descending: true,include_docs:true})
		.then(function(result){
			$rootScope.$broadcast('refrescar',result.rows);			
		});		
	})
  });
})
.controller('newsController',function($scope){
        $scope.notas='';
	$scope.$on('refrescar',function(event,news){
		$scope.$apply(function(){
                      $scope.notas = news;
                })
	})
})

Primero veamos todo el archivo en panorama y notaremos que el módulo ‘starter’ tiene propiedades “.run” y “.controller” que hemos definido. Esto se puede notar porque no hay “;” que los separe justo en la línea anterior. Ahora revisemos las líneas nuevas:

  • Línea 31: definimos el controlador ‘newsController’ y la funcion asociada que utiliza la entidad $scope. $scope es una entidad AngujarJS que identifica al ámbito definido en la vista que para nuestro caso es ‘index.html’ pero solamente en la sección donde está “ng-controller” definida. Para ponerla simple, nos permite declarar variables y funciones que serán visibles dentro de la vista.
  • Línea 32: declaramos una variable en el entorno llamada “notas”
  • Línea 33: Si la replicación envía eventos “paused”, pues es necesario que los recibamos en alguna parte así que aquí definimos que para cuando se reciba el evento ‘refrescar’, ejecutemos la función anexa la que toma dos parámetros: el evento y el objeto asociado donde están nuestros documentos.
  • Línea 34: En angular, si cambiamos el modelo tenemos que “aplicar” el cambio en el $scope
  • Línea 35: Finalmente, asignamos el array de documentos a una variable de entorno llamada “notas”

En la línea 34, sin notarlo, también estaremos usando una de las grandes potencias de AngularJS: “two-way data binding” que es el refresco automático de la vista cuando cambien las variables del entorno. Créanme que es mas fácil verlo que explicarlo.

Veamos, ya el controlador tiene los datos, así que vayamos a la vista a mostrar los datos. Para esto agregamos el siguiente código a “index.html”:

<ion-content>


 Hay {{notas.length}} noticias



<div class="list" ng-repeat="noticia in notas">


<div class="card">


<div class="item item-divider">{{noticia.doc.fecha}}</br>{{noticia.doc.titular}}</div>




<div class="item item-text-wrap"><b>{{noticia.doc.resumen}}</b></div>


			


<div class="item item-divider">Autor: {{noticia.doc.autor}}</div>


		</div>


	  </div>


      </ion-content>

Otra vez el línea por línea:

  • Línea 23: mostramos el tamaño de la variable notas y como es un Array de documentos acepta la propiedad length
  • Línea 24: Hacemos una lista para que se vean las noticias algo ordenadas mediante la clase CSS “list” y dejamos abierto el tag para agregarle otra directiva
  • Línea 25: al <div> de la lista le agregamos una directiva Angular para iterar en los elementos del array “notas” y a cada elemento lo conoceremos como “noticia”
  • Línea 26 a la 30: Cada elemento del array trae mucha información desde Cloudant, pero nos interesa uno en particular que es la propiedad “doc” que tiene todos los campos que hemos definido, así que lo incluimos. Además, incluimos el nombre de cada campo del documento noticia.

Graben y listo. Ya tienen su primera aplicación en Ionic con integración de base de datos local PouchDB y remota en Cloudant!!. Para ver más allá de lo evidente, pueden hacer la prueba agregando otro documento en Cloudant para que vean la potencia de la sincronización con PouchDB. Ya saben como agregar documentos a Cloudant así que tomen su reloj y tomen el tiempo que toma mostrarse la nueva noticia. Recuerden usar el formato para el campo “_id”: “news_fecha_autor_XXX”. En mi caso, el refresco fue casi instantáneo.

Y con esto podemos dar por terminado este largo Post con la satisfacción de tener una app completamente funcional. Para los que recién comienzan, los tags que vienen del mundo Ionic pueden confundir (<ion-pane>,<ion-content>, etc) pero no hay nada como leerse la documentación en la página de Ionic Framework pues está con ejemplos y todo. Para el caso de AngularJS, el peligro es que en javascript hay muchas maneras de hacer lo mismo y ya les adelanto que lo que les he explicado aquí es una forma muy simple de hacer las cosas. Una aplicación real hace la separación de la lógica en varios módulos, mientras que nosotros hemos usado uno solo para todo. Igual con las vistas, se suele tener muchas y no una sola. En lo que se refiere a Cloudant, hemos utilizado la instancia remota solamente cuando se sincroniza y luego la consulta a los datos ya es hecha localmente al PouchDB por lo que nuestro consumo será muy bajo. Además, si bien la sincronización “live” es muy potente, en una app real verán que a veces es mejor hacer una sincronización manual, sobre todo si sabemos que los cambios no se generan a cada rato, lo que nos permitirá ahorrar aún mas en Cloudant. Aún queda mas que aprovechar de Cloudant como las vistas (el famoso map/reduce de CouchDB), como manejar el almacenamiento, Sincronización filtrada  y algunas otras optimizaciones, todo con la seguridad de que sus datos están seguros y disponibles.

A ver si preparo el siguiente Post sobre vistas en Cloudant para poder combinar mas tipos de dato en el App y como generar sus apps para Android o iOS gracias a Ionic. Por ahora, jueguen con el app y modifíquenlo para que se vayan acostumbrando.

Mas información:

AngularJS: http://angularjs.org

Ionic Framework: http://ionicframework.com

PouchDB: http://pouchdb.com

IBM Cloudant: http://cloudant.com


  1. Arturo

    Excelente tutorial! mi consulta es la siguiente se podría decir que esta implementación es man rápida que (velocidad de acceso a los datos ) que de implementar en una base de datos relacional como mysql?

    • Si es mas rápida en la medida que uses los índices correctos. Ten en cuenta que usando nosql resuelves datos, sincronizacion y lo más importante es que organizas los datos tal como los vas a usar

    • Aqui mi respuesta ampliada:
      https://vpease.wordpress.com/2015/07/24/ionic-y-pouchdb-tips-para-rendimiento/

  2. Lucas

    Quisiera saber si este tutorial es compatible para celulares con una versión de android inferior a 4.0 . Por ejemplo la versión 2.3.
    Yo realicé una app con ionic e indexedDB y resulta que en celulares con versión de android inferior a 4.2.2 no funciona (pantalla blanca luego de splashscreen)

    Saludos y muchas gracias

    • También debería funcionar con Android 4.2.2. Para mayor compatibilidad, deberías usar Websql si vas a usar android 4

      • Lucas

        Websql , PouchDb y IndexedDB, son las 3 igualmente compatibles con este tutorial ? Saludos

      • PouchDB maneja Websql y IndexedDB sin problema.

  3. Luis

    Sigo los pasos pero no logro que en la carpeta LIB APAREZCA POUCH

    • Sólo para confirmar: paso 1: creas la app con ionic start nombre_proyecto, luego vas a la carpeta nombre_proyecto que se acaba de crear y ya puedes ejecutar : bower install pouchdb –save
      Si es que te sale error: bower no encontrado, ejecutas antes npm install -g bower y listo

  4. Que tal hermano, me gustó mucho tu curso, quiero hacerte saber de algunos errores que tienes, para que los que hagan el curso después no sufran haha ahí van, son detalles muy pequeños:

    La instalación de bower es dentro de la carpeta del proyecto:

    c:\>bower install pouchdb bower install pouchdb <–Así debería ser.

    al final Tienen que agregar RootScope, a su propiedad .run:

    .run(function($ionicPlatform,$rootScope)

    el truco es fijarse en el ultimo pedazo de código ese te aclara todo, Saludos, procedo a la parte 2!.

    • Gracias por el comentario. Puedes instalar Bower localmente como lo haces tú, pero no lo podrías usar fuera de tu proyecto.
      Bower es demasiado útil, por lo que en mi configuración lo tengo global para poder utilizarlo en todos mis proyectos.

      Sobre la instalación de los componentes, tienes razón. Todos los componentes deben ser instalados dentro de la carpeta del proyecto. Voy a hacer la corrección
      Saludos

    • Corrección hecha.

  5. fdquinones

    Excelente tutorial, solo por agregar me parece que en la linea de codigo 22 db.replicate.from(remote),{live:true,retry:true}); , se encuentra con error ya que esta con un paréntesis cerrando en un lugar incorrecto, debería que dar así: db.replicate.from(remote,{live:true,retry:true});

    • De acuerdo. Ya lo estoy corrigiendo

  1. 1 Quora

    How do I make my hybrid Android app that uses PouchDB for storage run on an Android 4.2.2 or less?

    The post is in English but you can follow the code steps with no problem.https://vpease.wordpress.com/2015/05/09/ionic-framework-pouchdb-y-cloudant-la-combinacion-perfecta-totalmente-expuesta-parte-01/

  2. 2 Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta Parte 02 | Víctor Pease

    […] Esta es una continuación de la serie sobre desarrollo en móviles que comencé aquí. […]

  3. 3 Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta Parte 03 | Víctor Pease

    […] 2 de esta serie. Para los que recién llegan, no hay un download del código, así que vayan a la Parte 1 para que hagan el código paso a paso con el […]

  4. 4 Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta Parte 04 | Víctor Pease

    […] es una continuación de la serie sobre desarrollo en móviles que comencé aquí. Les recomiendo comenzar a escribir el código fuente desde la parte 1 ya que no se publica el […]

  5. 5 Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta Parte 05 | Víctor Pease

    […] es una continuación de la serie sobre desarrollo en móviles que comencé aquí. Les recomiendo comenzar a escribir el código fuente desde la parte 1 ya que no se publica el […]

  6. 6 Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta Parte 06 | Víctor Pease

    […] es una continuación de la serie sobre desarrollo en móviles que comencé aquí. Les recomiendo comenzar a escribir el código fuente desde la parte 1 ya que no se publica el […]

  7. 7 Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta Parte 07 | Víctor Pease

    […] es una continuación de la serie sobre desarrollo en móviles que comencé aquí. Les recomiendo comenzar a escribir el código fuente desde la parte 1 ya que no se publica el […]

  8. 8 Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta | Víctor Pease

    […] Part 1 […]

  9. 9 Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta parte 08 | Víctor Pease

    […] es una continuación de la serie sobre desarrollo en móviles que comencé aquí. Les recomiendo comenzar a escribir el código fuente desde la parte 1 ya que no se publica el […]

  10. 10 Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta parte 09 | Víctor Pease

    […] es una continuación de la serie sobre desarrollo en móviles que comencé aquí. Les recomiendo comenzar a escribir el código fuente desde la parte 1 ya que no se publica el […]

  11. 11 Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta parte 10 | Víctor Pease

    […] es una continuación de la serie sobre desarrollo en móviles que comencé aquí. Les recomiendo comenzar a escribir el código fuente desde la parte 1 ya que no se publica el […]

  12. 12 Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta parte 11 | Víctor Pease

    […] es una continuación de la serie sobre desarrollo en móviles que comencé aquí. Les recomiendo comenzar a escribir el código fuente desde la parte 1 ya que no se publica el […]

  13. 13 Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta parte 12 | Víctor Pease

    […] es una continuación de la serie sobre desarrollo en móviles que comencé aquí. Les recomiendo comenzar a escribir el código fuente desde la parte 1 ya que no se publica el […]

  14. 14 Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta parte 13 | Víctor Pease

    […] es una continuación de la serie sobre desarrollo en móviles que comencé aquí. Les recomiendo comenzar a escribir el código fuente desde la parte 1 ya que no se publica el […]




Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s



%d bloggers like this: