Vemos el binding de datos desde componentes hijos hacia los padres y el uso de las propiedades notify, para indicar que queremos que se notifiquen cambios a los padres en componentes Polymer.
En el ejemplo del artículo anterior hemos hecho uso de binding entre componentes, pero solo hemos enviado datos del padre hacia el hijo. Podría darse el caso que desees también bindear y enviar datos desde el hijo hacia los padres.
Esta parte en Polymer no se hace automáticamente, puesto que tendremos que configurar el hijo explícitamente para decirle que, en caso de binding en una propiedad, se envíen los datos hacia el padre. Dicho de otra manera, necesitamos decirte a Polymer si deseamos que se notifique al padre de los cambios realizados en propiedades en el hijo.
Declaración notify
Que los datos bindeados viajen de los componentes hijos a los padres se consigue por medio de una declaración que todavía no habíamos visto en el Manual de Polymer. Es el atributo "notify" que usamos al declarar propiedades de componentes.
- Notify de manera predeterminada vale "false", produciendo que no se notifique a los padres. Es decir, si se cambian en el hijo propiedades que nos vienen bindeadas del padre, no se enviarán los nuevos valores.
- Si declaramos la propiedad y asignamos "true" a su valor "notify" entonces sí que viajará el dato actualizado desde el hijo al padre.
Para hacer un ejemplo de este caso hemos recurrido al mismo caso que se ha solucionado anteriormente. Volvemos al ejemplo del párrafo que puede estar expandido o colapsado, pero le vamos a aplicar unas modificaciones.
Componentes no representacionales
El cambio fundamental en este ejemplo es que nuestro componente romper-cadena no mostrará ninguna cadena. Es un componente que no tiene representación alguna en el template.
Los componentes no-representacionales son comunes en el desarrollo basado en Web Components. Son componentes que no muestran ninguna información, sino que simplemente resuelven alguna necesidad sin producir salida en la página. Son generalmente "helpers", ayudantes para llevar a cabo ciertas tareas.
En el catálogo de elementos de Polymer encontramos diversos componentes no representacionales, como el "iron-ajax", que realiza una conexión Ajax, los componentes paper-styles, que simplemente declaran reglas de CSS que podrás usar a lo largo de la aplicación para trabajo con layouts, colores, tipografías… "iron-signal" que simplemente se encarga de enviar señales a diversos componentes cuando ocurren cosas de las que deban estar informados, etc.
En nuestro ejemplo actual hemos alterado el componente romper-cadena, que ya vimos en el artículo Registro de propiedades, para que no tenga representación alguna.
Simplemente hemos quitado el TEMPLATE, de modo que no pintará nada en la página cuando se incluya en otros componentes.
Componente rompe-cadena-no-representacional
En este componente es donde hemos quitado toda la presentación del template. Pero hay un cambio muy importante que debemos mostrar.
Como ahora no representa él mismo la cadena recortada, tendrá que comunicársela al padre. Esto es sencillo de conseguir con la propiedad "notify". La propiedad que tiene que notificarse al padre es "recorte" que ahora nos queda así:
recorte: {
type: String,
computed: 'calculaRecorte(len, str)',
readOnly: true,
notify: true
}
Declaración readOnly
Además aprovechamos para ver en funcionamiento otra de las posiblidades al declarar propiedades de componentes, que es "readOnly". En este caso es muy interesante porque la propiedad de recorte es algo que calcula el componente "rompe-cadena-no-representacional" y que no se debería modificar desde fuera, porque podría producirse un mal-funcionamiento del componente.
Esta propiedad declarada como readOnly no es que sea una constante, pues dentro del componente dueño de la propiedad la puedo modificar. Simplemente indica que desde fuera no la podrán "setear".
Ojo, como verás a continuación sí se pueden bindear propiedades desde otros componentes a propiedades readOnly, simplemente, aunque se cambie el valor desde fuera, no se permitirá la acción por haber sido declarada como de solo-lectura.
Componente mostrar-recortar-representacional
Para hacer este ejemplo hemos realizado sobre todo unos cambios en el template del componente mostrar-recortar original. Básicamente, como el componente romper-cadena-no-representacional no muestra la cadena en cuestión, la vamos a tener que mostrar nosotros en el template. Nos quedaría así:
<template>
<rompe-cadena-no-representacional str="{{cadena}}" len="{{longitud}}" recorte="{{recorte}}"></rompe-cadena-no-representacional>
<p>
{{recorte}}
<iron-icon icon="{{icono}}" on-tap="mostrarRecortar"></iron-icon>
</p>
</template>
Aquí la gracia es que al componente rompe-cadena-no-representacional le estamos bindeando ahora la propiedad "recorte". Esa propiedad es la de solo lectura, asi que desde el componente rompe-cadena-no-representacional se le asignará el valor que corresponda. Cómo lo haga ya es algo que queda encapsulado en el componente hijo que se encarga de esa tarea, nosotros solo le estamos entregando el nombre de una propiedad para que lo rellene.
El resto del componente es exactamente igual que lo que teníamos en el artículo anterior.
Esperamos que lo puedas seguir, recuerda ver el código en GitHub en el repositorio del manual y hacer tus propias pruebas y prácticas para seguir afianzando los conocimientos.
Listados completos de los componentes
Sobretodo pensando en las personas que descargan los PDF de los manuales, vamos a presentar aquí el código completo de los componentes. Comenzamos por el componente más importante realizado en este artículo:
Componente mostrar-recortar-representacional: Este es el componente padre, el que se encarga de mostrar la cadena recortada, con un icono sobre el que se puede hacer clic para poder ver el contenido de la cadena completa (sin aplicar el recorte).
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="rompe-cadena-no-representacional.html">
<link rel="import" href="../../bower_components/iron-icon/iron-icon.html">
<link rel="import" href="../../bower_components/iron-icons/iron-icons.html">
<dom-module id="mostrar-recortar-representacional">
<template>
<rompe-cadena-no-representacional str="{{cadena}}" len="{{longitud}}" recorte="{{recorte}}"></rompe-cadena-no-representacional>
<p>
{{recorte}}
<iron-icon icon="{{icono}}" on-tap="mostrarRecortar"></iron-icon>
</p>
</template>
<script>
Polymer({
is: "mostrar-recortar-representacional",
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';
}
}
});
</script>
</dom-module>
Componente rompe-cadena-no-representacional: Este es el componente hijo, que es no-representacional porque no muestra nada en su template. De hecho, ni siquiera tiene template. Simplemente realiza el recorte sobre una cadena y lo expone al padre en una propiedad llamada "recorte" que tiene configurado un binding hacia arriba, gracias al ser una propiedad con "notify" a true.
<link rel="import" href="../../bower_components/polymer/polymer.html">
<dom-module id="rompe-cadena-no-representacional">
<script>
Polymer({
is: 'rompe-cadena-no-representacional',
properties: {
len: {
type: Number,
value: 20
},
str: {
type: String,
value: ''
},
recorte: {
type: String,
computed: 'calculaRecorte(len, str)',
readOnly: true,
notify: true
}
},
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(' '))) + '...';
}
});
</script>
</dom-module>
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...