> Manuales > Manual de Polymer

Cómo se realiza binding entre componentes Polymer, cuáles son las herramientas que en Polymer facilitan la interoperabilidad entre componentes.

El binding es un enlace a un dato, de modo que todos los elementos que estén "bindeados" a ese dato puedan recibir cualquier cambio de manera automácia. Esto ya lo conocimos en el artículo de introducción al binding en Polymer.

Ya vimos que dentro de un componente puedo bindear datos, generalmente propiedades, hacia el template. De modo que si cambia esa propiedad también cambie la vista sin que tengamos que hacer nada. Ahora vamos a ver cómo entre componentes también puede producirse el binding, permitiendo que un dato que se usa en un componente también pueda viajar hacia otros componentes que lo necesiten.

Binding a través de las propiedades / atributos

En realidad enviar información por medio de binding a otros componentes es muy sencillo. Ya hemos enviado datos literales varias veces cuando usamos los componentes. Por ejemplo recuerda el componente "romper-cadena" que mostramos en el artículo Registro de propiedades: tipos, valores y otras configuraciones.

<rompe-cadena str="Estas son las dos caras de la moneda" len="10"></rompe-cadena>

Al usar ese elemento le pasamos datos literales para adaptar su modo de funcionamiento. Cada vez que lo usamos le enviamos datos distintos para mostrar diferentes cadenas con sus recortes. Hasta ahora simplemente le hemos enviado datos literales, pero también podemos enviarle datos variables.

Por ejemplo imagínate que estás dentro de un componente y tienes la cadena a romper en una propiedad llamada "cadena". Podríamos usar el elemento anterior indicándole que su propiedad "str" esté bindeada con la variable "cadena".

<rompe-cadena str="{{cadena}}" len="10"></rompe-cadena>

Lo hemos explicado muy rápido, pero ahora lo veremos con un ejemplo completo para que te quede perfectamente claro.

interoperabilidad entre componentes

En una aplicación basada en componentes (y esto aplica a todo el desarrollo basado en el estándar Web Components) tenemos una arquitectura basada en Custom Elements, por medio de un árbol de elementos que interactúan entre si para cumplir el propósito de las aplicaciones. Esa actuación coordinada entre los componentes, necesaria para la resolución de los problemas se conoce como interoperabilidad. En Polymer se resuelve permitiendo que los componentes se pasen datos los unos a los otros por medio del binding y también gracias a la comunicación de eventos personalizados.

Pongamos que queremos hacer un componente que muestre un párrafo en un espacio reducido de la página. El párrafo tiene mucho texto así que a veces se puede recortar. Pero también queremos que el usuario pueda verlo entero si lo requiere, pulsando un botón para evitar ese recorte.

Nota: Esta tarea es bastante simple como para hacer un único componente, quizás no es el mejor ejemplo, pero piensa en una aplicación pequeña o mediana, la cantidad de subtareas que puede tener. Cada una de ellas se encapsula en un componente y eso permite que su complejidad sea pequeña, facilitando el desarrollo, pero sobre todo el mantenimiento, y ubicando perfectamente cada cosa en su sitio.

Para esta tarea podemos pensar en dos componentes distintos. Uno que se encargue únicamente del recorte de la cadena y otro que se encargue de la interacción con el usuario, permitiendo captar el evento de recorte o despliegue del párrafo cuando se pulsa el correspondiente botón. Quebrar esta tarea en dos componentes todavía es una solución más acertada cuando pensamos que ya existe el componente de romper una cadena, porque lo tenemos desarrollado ya en un mencionado artículo anterior.

Así que tendremos dos componentes uno que envuelve al otro.

En nuestro componente padre "mostrar-recortar" tendremos el siguiente template:

<template>
  <p>
    <rompe-cadena str="{{cadena}}" len="{{longitud}}"></rompe-cadena>
    <iron-icon icon="{{icono}}" on-tap="mostrarRecortar"></iron-icon>
  </p>
</template>

Como ves, unos componentes incluyen a otros y así se va generando ese árbol de componentes que son capaces de hacer funcionar una aplicación completa.

En este caso tenemos el componente rompe-cadena, que se encarga de romper una cadena a una longitud dada. Si te fijas, la cadena y la longitud no se entregan de manera literal, sino que las tenemos bindeadas a dos propiedades del componente padre ("cadena" y "longitud").

Luego, en vez de un botón propiamente dicho, hemos usado un icono, del catálogo de elementos de Polymer. Lo divertido es que la imagen del icono que se debe mostrar no se especifica tampoco, sino que está bindeada la propiedad "icono". Aquí tienes otro ejemplo de interoperabilidad entre componentes y lo hacemos así simplemente para que, cuando el párrafo está expandido se muestre un icono de contraer y cuando el párrafo está contraído se muestre un icono distinto. Bueno, en realidad es el mismo elemento iron-icon, solo que indicando valores distintos al atributo "icon", con lo que cambiará el aspecto.

Nota: Ten cuidado cuando uses elementos del catálogo de componentes de Polymer, puesto que los tendrás que importar debidamente y haberlos descargado previamente con Bower. Esto ya lo vimos al tratar los capítulos de usar elementos de Polymer.

Hay otra cosa importante en este template y es que el icono tiene un evento. No hemos llegado a hablar de eventos todavía, pero básicamente "on-tap" nos sirve para detectar un "click" o un "tap" (clic de dispositivos touch) sobre ese icono. En ese evento se invoca un método del propio componente llamado mostrarRecortar() que veremos enseguida.

Ahora veamos cómo hemos registrado este componente, en el script Javascript. Aunque mostrarmos el listado completo, nos centraremos primero en la declaración de propiedades.

Polymer({
  is: "mostrar-recortar",
  properties: {
    cadena: String,
    longitud: {
      type: Number,
      value: 20
    },
    longitudDefault: Number,
    icono: {
      type: String,
      value: 'remove'
    }
  },
  ready: function() {
    if(this.longitud == 0){
      this.icon = 'add';
    }
  },
  mostrarRecortar: function() {
    if(this.longitud > 0) {
      this.longitudDefault = this.longitud;
      this.longitud = 0;
      this.icono = 'add';
    } else {
      this.longitud = this.longitudDefault;
      this.icono = 'remove';
    }
  }
});

Tengo cuatro propiedades que paso a comentar:

Ahora veamos los métodos:

Como las propiedades están bindeadas al template, en los métodos que orquestan el funcionamiento del componente simplemente me dedico a cambiar sus valores. Además, lo interesante en este ejemplo es que algunas propiedades viajan hacia los componentes hijo, produciéndose la interoperabilidad.

Nota: Es importante mencionar con respecto al componente rompe-cadena que hicimos en el artículo sobre el Registro de propiedades que hemos tenido que hacer una pequeña modificación para adaptarlo a estas necesidades y es el hecho de evaluar también si la longitud es igual a cero, en cuyo caso hemos dicho que no queríamos realizar recorte.

calculaRecorte(len, str){
       if (str.length <= len || len == 0) {
         return str;
       }
       var recortada = str.substr(0, len);
       return recortada.substr(0, Math.min(recortada.length, recortada.lastIndexOf(' '))) + '...';
 }

El código completo de los componentes que hemos visto en este artículo lo puedes encontrar en GitHub, en el repositorio del Manual de Polymer.

En este artículo hemos visto bastante información sobre cómo bindear datos entre componentes, pero todavía nos quedan cosas interesantes que analizar con detalle, como es el caso del bindeo de datos desde los hijos a los padres, que veremos en el próximo capítulo del Manual de Polymer.

Miguel Angel Alvarez

Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...

Manual