"> Tutorial Polymer: Programar una aplicación To-Do List

Tutorial Polymer : Programar una aplicación To-Do List

Tutorial Polymer programar todo app

El año pasado Google anunció la versión 1.0 de Polymer, se trata de una librería que combina HTML5, CSS y Javascript para crear componentes web muy buenos y reutilizables orientados al desarrollo web actual y modular.

Polymer es la nueva revolución del HTML como lo conocemos hasta ahora, mejor conocida como Web Components que marcarán el comienzo de una nueva era en el desarrollo web basado en elementos/etiquetas personalizados, encapsulados e interoperables que extienden HTML en sí mismo. Así que, basándonos en estas nuevas normas, Polymer hace que sea más fácil y más rápido crear cualquier cosa, desde un botón, hasta una aplicación completa tanto para escritorio como para móviles.

Descargar tutorial Ver demo

 

¿Qué es Polymer?

Como ya hemos dicho es una librería que nos permite crear componentes webs personalizados. Podemos crear nuestras propias etiquetas de html5 y usarlas en cualquier lugar de nuestras webs.

Los web components o componentes webs son un conjunto de estándares de la w3C que nos permiten la creación de widgets o componentes reutilizables en las aplicaciones web.

Piensa que html ya nos proporciona un grupo de componentes como <table>, <button>, <form>, etc. Cada elemento tiene su propio estilo y su propia API de atributos, métodos y eventos.

Gracias a Polymer podemos ampliar ese vocabulario de etiquetas creando las nuestras, estas etiquetas html5 personalizadas deben tener como mínimo un guión: <tu-etiqueta>.

Por ejemplo, para insertar el mapa de Google Maps debemos usar un script atroz e insertar lo siguiente:

Y si lo transformamos en un web component la cosa se nos quedaría así:

¿A que mola?

Polymer 1.0 reduce el tamaño de tu código y además hace más rápido el llamado data-binding, creando una experiencia de interacción con nuestra app que va como la seda.

El data-binding es la unión de datos dinámicos ya sea texto o HTML en las diferentes partes del árbol DOM de nuestro documento.

El binding a secas significa enlazar la información que tenemos en el “scope” de nuestro javascript con lo que mostramos en el HTML.

¿Qué vamos a desarrollar en este tutorial?

Vamos a crear una aplicación to-Do colaborativa; que nos permita crear tareas, almacenarlas en una lista y todo esto en tiempo real, es decir, que nuestra app sincronizará el estado de las tareas agregadas (completadas, etc) con todos los dispositivos conectados a ella.

Para hacer la estructura de la aplicación usamos Polymer 1.0 y PubNub para enviar y recibir actualizaciones entre los dispositivos conectados y sincronizar estados de las tareas.

Programar aplicación Polymer

La app tendrá 3 ficheros:

  • un index.html donde declaramos el elemento <todo-app>
  • un elemento todo-app.html que formará el sidebar, header, y contendrá el elemento todo-element.html
  • un elemento todo-element.html que será el módulo de la task con el panel para editarla, usuarios, fecha, etc. Iteraremos las task en un bucle dentro del todo-app.html.

Forma de trabajar con Polymer 1.0

Para trabajar con Polymer lo primero que debes hacer es importar los elementos en tu proyecto antes de usarlos. Un uso estándar de polymer sería algo como esto:

Una de las cosas más molonas de Polymer es que usa Material Design como lenguaje de diseño, con todas sus especificaciones visuales e interacciones llevadas tanto para apps móviles como para aplicaciones web.

Estos elementos de material los llamamos en Polymer paper elements, están hechos para adaptarse a cualquier dispositivo y tienen un aspecto visual muy bueno, de app profesional.

Configurando nuestro entorno local para Polymer

Si intentas abrir tu proyecto de polymer file://<tu-proyecto-polymer> en el navegador, la consola de éste te mostrará una hermosa petada:

instalar-polymer-local

Puedes ver que nos da problemas el CORS (Cross Origin Resource Sharing), no podemos cargar los datos por limitaciones de seguridad.

Así que para ejecutar tu aplicación polymer debes subirla a un servidor web, por ejemplo Github Pages.

Ahora bien, para el entorno de desarrollo local vamos a configurar un sencillo servidor en Python, no cuesta nada.

Instálate Python desde aquí, el proceso es simple. Si lo tienes instalado recuerda que para ver la versión de Python debes introducir el comando: python –version.

Abre el terminal o la consola y posiciónate dentro de la carpeta de nuestra aplicación (créala previamente con cualquier nombre), ahora debes introducir un comando u otro según tu versión de Python:

Arrancamos el servidor Python por ejemplo, en el puerto 8001

Arrancamos el servidor Python por ejemplo, en el puerto 8001

Elige el número de puerto que te apetezca, en mi caso el 8001.

Ya puedes ver el proyecto polymer desde el navegador -> http://localhost:8001/index.html

Si te descargas el tutorial ya completado podrás visualizarlo en tu localhost de esta forma.

1. Maquetando tu aplicación to-Do List con paper elements

1.1 Instalar Polymer

Primero instalamos Polymer y para ello nos ayudamos del gestor de paquetes Bower. Siempre verás que lo uso en mis tutoriales, si no lo sueles usar sigue estas simples instrucciones para instalarlo.

Ahora vamos a la consola y dentro del proyecto ejecutamos estos comandos para instalar Polymer:

El primer comando crea el fichero bower.json donde se añadirán los packages y dependencias que usemos, y nos preguntará una serie de datos sobre el proyecto (pulsa enter a saco hasta llegar al final).

Con el segundo comando bower nos instala Polymer incluyendo todos los scripts webcomponents.

Ahora crea un fichero  en la raíz del proyecto y carga el fichero webcomponents-lite.js en él:

1.2 Descargando los paper elements

Existen muchísimos paper elements que tienen muy buena pinta, por lo que si te apetece escoger otros para el tutorial eres completamente libre de hacerlo.

Puedes ver todos los elementos de Polymer en este catálogo (estilo tabla periódica).

Para bajarte cualquier elemento debes usar este comando en la consola:

Esquema elementos de app polymer

Los elementos que vamos a usar en el tutorial de polymer son:

  • paper-checkbox: el botón con los estados checked/unchecked para las tareas. Ver elemento.
  • iron-input: para controlar la funcionalidad de los input
  • paper-input: elemento input al estilo Material Design
  • paper-drawer-panel: dota de un aspecto de app a nuestro proyecto (el típico sidebar de las apps de android)
  • paper-button: crea botones material como el de “Editar”
  • paper-fab: para el botón redondo de material que está flotando por encima de todo
  • paper-menu: para crear el menú lateral con las tareas ya completadas
  • iron-icons: nos proporciona los iconos de material design

Vamos a instalar todos los elementos a saco, mete estos comandos en tu terminal o consola:

Ya está listo todo para importar, usar esos elementos y crear nuestro propio elemento personalizado.

2. Creando nuestro propio elemento/etiqueta to-Do

El fichero index.html debes actualizarlo con esto:

Añadir <meta name="viewport" content="width=device-width, initial-scale=1"> dentro de la etiqueta <head> hace que la app se muestre correctamente en dispositivos móviles y tablets.

Luego tenemos el fichero webcomponents y debajo importamos el fichero todo-app.html, que es el component/etiqueta personalizada que crearemos a partir de otros componentes.

<body fullbleed unresolved> le dice a Polymer que el <body> debe ocupar toda la pantalla, y que además se espere hasta que todos los elementos sean resueltos (cargados) antes de mostrar cualquier cosa, evitando así el odioso efecto FOUC.

2.1 Estructura de un elemento o etiqueta personalizada

Esta es la estructura general de un elemento que queramos crear con Polymer:

En el <head> se importan las dependencias, en este caso la librería general de Polymer: polymer.html. Como ya adelantamos antes, unos componentes se pueden crear en base a otros, así que no solo tendrás dependencias de polymer, si no también de otros elementos.

Mientras en la etiqueta <dom-module> colocamos en su atributo id el nombre del elemento que estamos generando. Esta etiqueta es la raíz de nuestro custom element / elemento personalizado, es propia de Polymer y en ella agruparemos los CSS, HTML y JS.

Dentro de la etiqueta <dom-module> creamos otra etiqueta <template> donde meteremos el contenido del DOM local, osea, todo el código html del componente.

Finalmente en el script Polymer({}) registramos el elemento que vamos a crear y escribimos la lógica del componente en javascript. Indicamos además una serie de parámetros como el nombre y los atributos, los cuales se declaran dentro de properties:{}.

En breve ampliaremos información sobre esto.

2.2 Importando los elementos

Toca importar los elementos que nos descargamos en el paso 1.2 para poder utilizarlos.

Sitúate en la raíz del proyecto y crea una carpeta nueva llamada elements, y crea un fichero dentro de ella llamado /elements/todo-element.html.

En el fichero todo-element.html copia y pega la plantilla de arriba para crear un elemento personalizado de Polymer.

Después importa los elementos dentro de la etiqueta <head>:

Continuamos configurando la plantilla. Al botón clásico de material design <paper-button> le añadimos uno de estos iconos.

Vale, vamos a dedicarle una pequeña pausa al data-binding para aquellos que nunca han usado Polymer.  Como puedes ver usamos todo el tiempo estos brackets {{}}, dentro de ellos enlazamos una propiedad (editing, task, etc, más adelante las definimos), estas propiedades siempre deben ir entre los brackets.

Este data-binding que hemos hecho es de dos vías (two-way).

Te recuerdo que el data binding o enlace de datos puede hacerse por una vía (one-way) o dos vías (two-way):

One-way binding: la información sólo fluye desde el script hasta la parte visual, osea, desde el ámbito de la variable js hacia la representación de la información en el HTML. Lo conseguimos con la sintaxis de los corchetes:

Ese dato estarías trayéndolo desde el scope y mostrándolo en la página. La información fluye desde el scope hacia la representación, quiere decir que, si por lo que sea se actualiza el dato que hay almacenado en el modelo (scope) se actualizará automáticamente en la presentación (página).

Two-way binding: En este segundo caso la información fluye desde el scope hacia la parte visual (igual que en “one-way binding”) y también desde la parte visual hacia el scope. Lo logramos con la síntaxis “moustache” de los brackets:

En este caso cuando modifiquemos <paper-input value="{{task}}"> y cambiemos su valor, la propiedad task en el atributo value se actualizaría automáticamente con el nuevo valor. Además, gracias al doble binding (two-way) en este caso, cuando el usuario cambie el valor del atributo el scope se actualizará automáticamente también.

Si te parece muy liosa mi explicación échale un vistazo a la documentación de Polymer sobre data binding.

Antes de seguir fíjate en que hemos envuelto los elementos con el elemento <paper-material>, el cual tiene un atributo elevation con el valor 1. Esto generará una sombra para dar profundidad al elemento, al más puro estilo material design.

Este sería nuestro todo-element visualmente.

Este sería nuestro todo-element visualmente.

2.3 Definiendo las propiedades de nuestro custom element

Ahora vamos a definir estas propiedades que usamos entre los brackets {{nombre-propiedad}} y que se renderizarán mediante data-binding en el DOM del index.html final del proyecto (el que puedes ver ejecutando la demo del tutorial con el servidor Python).

Las propiedades/properties que vamos a usar son:

  • user: La persona que añade o completa una tarea/task
  • task: La tarea que ha sido añadida
  • time: La fecha de creación de la task
  • rid: Un ID random que lo usaremos para coordinar las task por PubNub
  • completed: Independientemente de que la tarea esté completada o no lo esté
  • editing: Si el usuario está editando la tarea

Y ahora las definimos en la lógica de nuestro elemento personalizado todo.html:

Puedes ver que cada propiedad la declaramos con su nombre, el tipo de dato y un valor por defecto.

Con el data-binding se ocultará <paper-item hidden="{{editing}}" id="task">{{task}}</paper-item> en el momento en que pulsemos en el icono editar de la tarea.

La propiedad editing pasará a ser true una vez se llame a la función doEdit. Cuando es true oculta el botón de editar y muestra un input para editar la task además del botón redondo verde con el icono done, de esta forma confirmas que has editado la tarea. Si vuelves a pulsar en el icono verde se vuelve a llamar a la función doEdit y todo elemento visual vuelve a su estado anterior además de editarse la tarea.

Las propiedades nativas de Polymer usan las síntaxis on-nombre-propiedad, y al pasarles una función no requiere el uso de brackets {{}}. En nuestro código lo hacemos así: on-tape="doEdit".

Por último, nos fijamos en la propiedad completed y vemos que es un observer, es decir, una función que se llamará cuando la propiedad completed cambie en el momento en que marcamos el checkbox. Para comunicarse con otros elementos este código lanza un evento 'complete' con nuestra tarea finalizada.

Si quieres saber más sobre las propiedades, y hacer más data binding con ellas, échale un vistazo a la documentación.

Ya tenemos el elemento to-Do creado, es hora de usarlo para nuestra app.

 

3. Creando la aplicación

Nuestro index.html tiene un solo elemento, el <todo-app>, así que vamos a crearlo. Por ahora solo tenemos el todo-element.html, debemos agrupar este elemento junto a otros en un nuevo fichero que formará el elemento todo-app.

Empieza creando el archivo en /elements/todo-app.html.

3.1 Importamos los elementos para la app

Importamos nuestro elemento todo-element, creado antes, como cualquier otro elemento con <link href="../elements/todo-element.html" rel="import">.

También importamos el resto de elementos que vamos a usar:

3.2 Estructura básica

Los componentes paper-drawer-panel, paper-header-panel y paper-toolbar los usaremos para la estructura de nuestra aplicación y además se adaptan a diferentes pantallas.

La estructura básica del paper-drawer-panel es:

3.3 Crea tu Side Panel/columna lateral

Sidebar polymer tutorial

No existe el componente sidebar como tal, si no que lo creamos a partir de estos 3: <paper-menu>, <paper-material> y <paper-item>.

Comenzamos con paper-menu y vamos rellenando el contenido del Side Panel, mete este bloque completo dentro de las etiquetas <template></template>:

Templates con condicionales

El código de arriba tiene nuevas características de Polymer que debo explicar. Las templates se usan internamente para añadir funcionalidades como bucles y condicionales a tus elementos.

<template is="dom-if" if="{{!done.length}}"> tiene un condicional que funciona como un if, con la condición de que el array de tareas realizadas (done) tenga alguna completada. Si done está vacío y no tiene elementos, el condicional if {{!done.length}} se lee como not 0, por lo tanto lo evalúa como true.

De esta manera el bloque con “Las tareas completadas aparecen aquí” se mostrará solo cuando el array done esté vacío, y desaparecerá en cuanto el array se llene de tareas completadas.

Templates con bucles

El elemento <template id="done" is="dom-repeat" items="{{done}}"> es una forma efectiva de usar un bucle y mostrar los contenidos de un array. El atributo is=dom-repeat significa que se iterarán en el bucle todos los objetos del array done, como si fuera el clásico bucle foreach.

Asignamos el nombre de item a cada elemento/objeto del array, por ejemplo, si el contenido del objeto item fuera {task:”Estrangular a mi oficial”, user:”darth-vader”}, podemos acceder a las propiedades de ese objeto con {{item.task}} y {{item.user}}.

Al igual que en un foreach normal, también podrías añadir el atributo as=myTask para guardar el valor de cada objeto y luego acceder a sus propiedades tal que así {{myTask.user}}.

3.4 Contenido del Main Panel, cuerpo principal del elemento

Vamos a rellenar el segundo bloque de nuestra aplicación con polymer, este ocupará la mayoría de la pantalla y será donde podremos crear una tarea nueva con un breve formulario. Además aquí iteraremos el todo-element para mostrar las tareas que hemos creado.

 

Al igual que hicimos con el Side Panel, usamos el mismo condicional para comprobar en el primer <template> si hay tareas creadas y almacenadas en el array todo, si no hay tareas mostramos el mensaje genérico “No hay tareas…”, y si hay tareas iteramos en el <template id="tasks"> estas tareas.

Para crear una nueva tarea definiremos más adelante la función postTask, que se lanza con un evento on-tap cuando el usuario pulsa el botón de acción redondo (paper-fab) que usa material design. Hemos sacado este elemento fuera del bloque tal como indica las especificaciones de Material Design.

on-tap sería el equivalente a on-click, no obstante se recomienda usar on-tap ya que on-click no lanza el evento si otro dedo está tocando la pantalla. Para dispositivos móviles mejor usa siempre on-tap.

Por otro lado el elemento paper-input tiene un char-counter para mostrar la cantidad de caracteres que el usuario tipea en el formulario.

Puedes ver otras propiedades interesantes para este elemento en el catálogo de elementos.

Y aquí tienes el catálogo de iconos de polymer para <paper-fab>, por si quieres cambiar el icono add(+).

3.5 Implementando tu elemento todo-element.html

Tras declarar los array todo y done, obtenemos el valor de nuestro <paper-input id="tTask"> usando var tsk = this.$.tTask.value; Es fácil. Publicaremos nuestra task con PubNub en la parte 4 del tutorial, pero por ahora lo dejamos así.

Echa un vistazo a la función ready. Ésta se llamará una vez nuestro elemento se ha cargado y está listo para ser renderizado.

En ella registramos un event listener para 'complete', que se lanzará desde nuestro elemento personalizado todo-element.html, recuerda la línea: if(e){ this.fire('complete',this); }.

Controlamos en la función handleComplete, mediante la actualización de los campos con los datos de quienes completaron la tarea, y después publicaremos todos los colaboradores con PubNub.

4. Implementando en esta app las tareas compartidas

Polymer y pubnub

Vamos hacer que esta app to-Do sea en tiempo real, es decir, como si la estuvieran usando de forma colaborativa varios usuarios para realizar las tareas conjuntamente.

Para ello dijimos que vamos a usar PubNub para la entrega de datos en tiempo real.

Primero debes crearte una cuenta PubNubpara obtener una clave Publish Key y una clave Suscribe Key. Una vez registrado puedes encontrar las keys en el admin.

El plan gratuito de PubNub te proporciona el ancho de banda necesario para construir y testear tu aplicación To-Do.

4.1 El elemento PubNub en polymer

PubNub ya tiene predefinido un elemento en Polymer 1.0, descarga el <pubnub-element> usando bower con este comando en la consola:

Abre todo-app.html e importa este elemento:

4.2 Usando el elemento PubNub

Arranca el cliente PubNub usando el elemento <core-pubnub> con tus keys. Dentro de <core-pubnub> usamos un elemento llamado <core-pubnub-publish> para para transmitir un stream con los objetos todo.

El elemento <core-pubnub> y su contenido deben situarse dentro de la última tag <template> de tu elemento <todo-app>.

<core-pubnub-publish> se usa para enviar mensajes a todos los suscriptores de un canal. Este canal lo hemos configurado como "todo", así que todos los suscritos a todo recibirán las tareas.

Después, para publicar un mensaje, necesitamos acceder al <core-pubnub-publish> de la siguiente manera:

Volvemos atrás al todo-app.html y actualizamos handleComplete y postTask para que publiquen sus actualizaciones:

<core-pubnub-suscribe> nos va a suscribir al canal/channel todo, le pasamos dos valores: messages y presence. Ambos son arrays. Cuando el elemento PubNub recibe la actualización de un message o un presence, estos se insertarán en el array y lanzará un evento de message o de presence respectivamente. También tiene un on-callback que se lanza cada vez que ocurre un evento subscribe.

Podemos implementar esto de la siguiente manera en el script de tu todo-app.html:

Esto comprobará si un nuevo todo se está transmitiendo, o uno viejo está siendo completado. Polymer usa sus propios métodos para actualizar los arrays. Array.pop() no notificará a Polymer que ha habido un cambio, por lo que los elementos que ves en pantalla no se actualizarán.

Por eso se usa this.pop('nombreDelArray') (también push, shift, unshift, etc). Así pues usamos this.unshift(‘todo’, nuestroJSON); para añadir una tarea/task al comienzo del array todo, que después se actualizará desde nuestro dom-repeat del Paso 3.

4.3 Implementando la presencia/presence en tiempo real

Vuelve al admin de PubNub y  habilita la Presence pulsando en el botón verde “enable”. Presence detecta automáticamente cuando los usuarios entran o abandonan un canal. Lo vamos a usar para mostrar el número de usuarios conectados a la app y un icono.

Presence Polymer Pubnub

Dentro del elemento paper-toolbar añadimos:

Y así de fácil es como actualizamos el número de usuarios que hay conectados en tiempo real a tu aplicación:

Listo, el número de usuarios se actualizará en tiempo real.

 

Y eso es todo amigos, espero que disfrutéis de este tutorial para programar y desarrollar una to-Do List en Polymer. Si tenéis alguna duda o sugerencia no dudéis en comentar.

He añadido algunos estilos en la app que podéis modificar como os apetezca además de una generación de usuarios random y otras mejoras en el código final, recordad que los colores de material design combinan siempre bien entre ellos.

Referencias para el tutorial:

 

3 Comentarios

  1. Gus 16 agosto, 2016 Responder
  2. David 16 noviembre, 2016 Responder
  3. David 16 noviembre, 2016 Responder

Añadir un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *