> Manuales > Manual de Lit

Explicamos el binding a propiedad en los componentes desarrollados con Lit, destacando diferencias con el binding a atributo. Veremos cuándo es necesario hacer binding a propiedad.

Bindear a propiedades en componentes Lit

Ya desde el inicio del Manual de Lit hemos aprendido la sintaxis básica para hacer binding de valores en los templates de Lit. Además, en el artículo anterior vimos cómo realizar el binding a una propiedad boleana. Sin embargo, hay un caso especial que no hemos abordado todavía, el binding a propiedades, que toma especial importancia cuando el tipo del valor que se bindea es array o objeto.

Binding a atributo

Antes de ver cómo hacemos un binding a una propiedad, vamos a ver una vez más el binding a un atributo.

<a href=${this.url}>Un enlace a una url</a>

Como puedes ver, simplemente colocamos el nombre del atributo tal cual. El valor vendrá de la expresión que nosotros indiquemos en el binding, típicamente una propiedad del componente, pero podrían ser cosas más complejas.

<a href="${this.path}/${this.file}">Un enlace a un archivo con su ruta</a>

Los atributos son simplemente eso, atributos de la etiqueta HTML. Como has podido apreciar, funcionan igual que etiquetas normales, con la diferencia de que en este caso se trata de un custom element. La clave en este punto es que estamos enviando un valor al atributo de la etiqueta host de un componente y debido a ello Lit por debajo se encargará de hacer unas transformaciones del valor, que dependen del tipo en el que se haya declarado la propiedad en el componente. Esto lo vamos a explicar con algo más de detalle.

Conversiones implícitas de Lit al bindear a atributo

Al hacer el binding al atributo, Lit se encarga de hacer las conversiones adecuadas para que el valor tenga el tipo necesario en el componente que estemos utilizando.

Por ejemplo, ¿te acuerdas del componente dw-counter? Ese componente lo creamos para explicar cómo cambiar propiedades como respuesta a eventos en Lit.

Si refrescas la memoria recordarás que dw-counter tenía una propiedad llamada "counter" que estaba declarada con el type: Number. Por tanto podíamos bindear a atributo de esta manera:

<dw-counter counter=${this.numerito}></dw-counter>

Si this.numerito tuviese una cadena como "33", a pesar que le estemos bindeando una cadena y no directamente un número, el componente hará la conversión para que la propiedad counter tenga un valor de tipo number.

Lo mismo ocurre cuando le pasamos un literal al atributo counter:

<dw-counter counter="22"></dw-counter>

Los literales que pasamos a los atributos HTML son siempre cadenas, pero Lit hace el trabajo de cambiarle el tipo a numérico, porque la propiedad fue declarada con el { type: Number}.

Bindear a la propiedad

Hasta aquí no hemos dado ningún dato nuevo, que no sepas o no puedas haber analizado por tu cuenta a lo largo de artículos anteriores del manual. Ahora aprenderemos qué es el binding a la propiedad en Lit.

Siguiendo con el componente dw-counter, vamos a ver cómo podemos bindear a la propiedad y qué connotaciones tiene.

El binding a la propiedad simplemente se realiza con un caracter punto "." antes del nombre del atributo.

<dw-counter .counter=${this.numerito}></dw-counter>

¿Qué diferencia conseguimos con ese "."? pues es bien sencillo. Ahora estaremos enviando el dato directamente a la propiedad, sin usar el atributo de la etiqueta host. Lo más importante de esta situación es que al bindear a la propiedad no estamos pasando por el atributo, por lo tanto Lit no hace ningún tipo de conversión al sincronizar el valor a las propiedades.

Con binding a la propiedad, si this.numerito tuviera un valor numérico el componente funcionará perfectamente, porque le estamos pasando justamente lo que necesitaba. Pero en el caso que this.numerito tuviera una cadena de caracteres, dado que estamos atacando directamente la propiedad, no se realizaría ninguna conversión y al componente le llegaría siempre una cadena, por mucho que hayamos declarado como { type: Number} la propiedad counter.

Esa es la clave! con binding a propiedad estamos atacando directamente al valor de la propiedad y Lit no realizará ningún cambio en el valor que le estamos pasando. La propiedad podrá tener el type que sea, es indiferente! no habrá conversiones implícitas porque hemos asignado directamente a la propiedad.

Otra situación bastante aclaradora sería si this.numerito fuera un "undefined" porque no se haya inicializado. En ese caso, si hacemos el binding al atributo habrá una conversión de undefined al valor 0. En el caso que bindeemos a la propiedad, entonces al componente siempre le llegará undefined, sin hacer conversión alguna.

Con esto esperamos que hayas podido entender qué diferencias hay entre el binding a atributo (sin el punto) y el binding a la propiedad (con el punto). En resumen, si bindeamos a la propiedad estamos bindeando directamente a la propiedad Javascript.

Así visto, parece que no tenga mucha utilidad bindear a la propiedad, pues estamos perdiendo la ayuda de Lit a la hora de mantener los tipos, sin embargo, esta situación es importante para los tipos de objeto y array, como explicaremos a continuación.

Bindear a propiedades de arrays y objetos

Las diferencias entre el binding a propiedad o atributo pueden ser sutiles y para propiedades de tipo cadenas de caracteres la verdad es que cambia poco. Incluso para propiedades de tipo Number, si le pasamos verdaderamente un valor numérico funcionará exactamente igual, en la práctica, tanto si el binding es al atributo o a la propiedad.

Sin embargo, hay casos especiales en los que es esencial bindear a la propiedad, como cuando estamos enviando un valor de array u objeto.

Para ilustrar este caso vamos a mejorar un componente que ya habíamos desarrollado en el artículo Repeticiones o bucles en templates lit.

Recordar que allí vimos dos componentes: dw-tag y dw-tag-list. Nuestra mejora en este caso va a ser que dw-tag sea capaz de recibir un tag con un valor de objeto donde, además de pasarle el nombre del tag le pasaremos la URL donde tiene que enlazar al mostrar ese tag.

Componente dw-tag-list

La primera de las modificaciones que hemos realizado consiste en crear un array de objetos, cuando antes teníamos un array de strings. En el constructor creamos ese array de objetos.

constructor() {
    super();
    this.tags = [
        {
            name: 'Javascript',
            url: 'https://desarrolloweb.com/home/javascript',
        },
        {
            name: 'Lit',
            url: 'https://desarrolloweb.com/home/litelement',
        },
        {
            name: 'Web Components',
            url: 'https://desarrolloweb.com/home/web-components',
        },
        {
            name: 'Custom Elements',
            url: 'https://desarrolloweb.com/articulos/desarrollo-custom-elements-javascript-estandar.html',
        },
    ];
}

Lo más importante consiste en que ahora el template del componente envía los objetos mediante el binding de propiedad.

render() {
    return html`
        ${this.tags.length == 0
            ? html`<p>No tenemos tags que mostrar</p>`
            : html`
                <ul>
                    ${this.tags.map( tag => html`<li><dw-tag .tag="${tag}"></dw-tag></li>`)}
                </ul>
            `
        }
    `;
}

Puedes probar a quitar el binding de propiedad y poner binding de atributo y verás un error en la consola de Javascript, pues no se puede bindear un valor de objeto como atributo.

Componente dw-tag

A continuación veremos dw-tag, donde teníamos una propiedad "name" que simplemente vamos a quitar, porque ahora el nombre nos viene en uno de los datos del objeto bindeado. Debemos eso sí, definir la propiedad tag, de tipo objeto, ya que es lo que nos están bindeando ahora, un objeto con los datos completos del tag.

static properties = {
    tag: { type: Object },
}

En el método render usamos el objeto bindeado de esta manera:

render() {
    return html`
        <span>
            <a href="${this.tag.url}">${this.tag.name}</a>
        </span>`;
}

Eso es todo! Ahora hemos transformado el componente para que podamos experimentar con el binding a propiedad, enviando objetos. Esto está muy bien, porque el objeto tendrá la posibilidad de albergar muchos datos. Quizás no es tan importante para un componente tag, que es bastante simple, pero para otros componentes es más cómodo enviar un objeto con una serie de datos, que enviar una colección grande de atributos con datos primitivos.

El código completo de este ejemplo lo tienes en GitHub, tal como lo hemos dejado hasta este momento. En él verás además unas modificaciones mínimas en los estilos que hemos tenido que publicar para cambiar el color en los enlaces. Te dejamos a ti la tarea de analizar el código completo.

Miguel Angel Alvarez

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

Manual