Ver contenido

carlosazaustre.es carlosazaustre.es

WebComponents Nativos: Cómo pasar propiedades

🗓 | 💻 Desarrollo | 🕐 3 minutos de lectura | 💬 Comments

En un post anterior vimos como crear un webcomponent de forma nativa, sin librerías. Utilizando puro JavaScript y las APIS del navegador (CustomElements v1 y ShadowDOM v1)

Este artículo extiende el anterior para ver como podríamos pasar propiedades a un WebComponent.

Añadiendo una propiedad al Web Component

Voy a tomar el ejemplo anterior para añadir una propiedad al elemento.

Antes teníamos <sell-button></sell-button> ahora quiero añadir el texto del botón como propiedad tal que así: <sell-button text="Lo quiero!"></sell-button>

Así que tomando el código de sell-button.html que teníamos:

Vamos a realizar algunos cambios para que acepte propiedades. Modificamos un poco el <template> eliminando el texto del button y colocando un tag slot que nos permite añadir texto desde el exterior:

Los elementos pueden reaccionar ante cambios en sus atributos, si estos han sido definidos en otra de las funciones del ciclo de vida de un customElement en concreto en la función attributeChangedCallback que recibe como parámetros el nombre del atributo o propiedad, el valor que tenía anteriormente y el nuevo valor.

Aqui lo que vamos a hacer es cambiar el contenido textual del componente (gracias al tag <slot> que hemos añadido al template) por el nuevo valor

Observando cambios

Éste método sólo se disparará si hemos declarado el atributo o propiedad attrName en la función observedAttributes de la clase del elemento.

Es una función get de ECMAScript6, lo que significa que va a ser invocada automáticamente, en este caso cuando se dispare attributeChangedCallback y se ejecutará por cada uno de los atributos que tengamos en el array que devuelve la función. En este caso solo el atributo text.

Resumiendo, el contenido actualizado del Web Component sell-button será el siguiente:

Y para verificar que si se cambia el atributo, se refleja en el interior del template del componente, vamos a crear una función de setTimeout que pasados 3 segundos, modifique el valor de la propiedad text:

De esta forma, al cargar la página tendremos esto: Screen Shot 2017 03 22 at 13 15 40

Y después, tras cambiar el valor de text por el texto: "Lo quiero ahora!" tendríamos esto:

Screen Shot 2017 03 22 at 13 15 44

Puedes ver esto en funcionamiento en el siguiente CodePen

RECUERDA:

Prueba este ejemplo en una versión reciente de Chrome o en su defecto en Chrome Canary, ya que los HTMLImports no están soportados en Safari, Firefox ni Edge. Para eso necesitas usar el Polyfill de webcomponents

Añadiendo más de una propiedad

¿Y qué pasa si queremos utilizar más de una propiedad? En ese caso hay que hacer algo más de "fontanería". Imaginemos que ahora nuestro custom-element queremos que tenga ésta pinta y que ademas sus propiedades sean observables:

Bien, primero vamos a modificar el <template> ya que ahora con un único elemento <slot> no nos sirve, ya que tendremos dos propiedades. Vamos a añadir otro y los vamos a distinguir por la propiedad name:

Después añadimos la nueva propiedad intro a la función observedAttributtes:

También vamos a actualizar el constructor, añadiendo un par de variables "privadas" que guarden el valor de estos atributos para uso interno:

Después vamos a implementar dos funciones getter y setter de ECMAScript 6 que se invocarán cada vez que vayamos a acceder a la propiedad en cuestión. Es decir, si queremos acceder a this.intro o cambiar el valor de this.intro, se llamará automáticamente a la función get intro() en el primer caso y a la función set intro(val) en el segundo:

Lo único que hacemos aquí es que cuando queramos leer el valor de text o intro devolvemos el valor que tiene el atributo con this.getAttribute. Y cuando lo queramos modificar le pasamos el valor a la variable "privada" que habiamos declarado en el constructor.

Después modificamos la función attributeChangedCallback para que ante los cambios (si se producen) sea capaz de reflejarlos en el ShadowDOM:

Como name cambia según los atributos que se devuelven en el array de observedAttributes, name será text o intro según lo que se actualice.

Aquí hacemos una comprobación si existe el shadowRoot ya que en un primer momento, cuando declaramos el componente con propiedades, este método se invoca pero el ShadowDOM no está listo, entonces hay que hacer esta pequeña comprobación, para cuando lo esté poder hacer una llamada a querySelector buscar el <slot> con el nombre que hayamos definidos y pasarle el valor de this.intro o this.text según el atributo que se haya cambiado.

Y por último, actualizamos el método connectedCallback para que añada los valores de las propiedades al ShadowDOM en su creación:

Resumiendo, el componente completo sería así:

Si en nuestro index.html modificamos el componente con el nuevo atributo, tendríamos este resultado:

Screen Shot 2017 03 22 at 17 41 05

Y si hacemos como con el ejemplo anterior, una función de timeout que cambie las propiedades pasados 2 segundos, tendremos el nuevo resultado:

Screen Shot 2017 03 23 at 09 18 08

En el mismo CodePen tienes el código y demo de este ejemplo (En este caso en el archivo sell-button-copy.html.

Conclusión

Con esto hemos visto como funciona el estándar de Web Components de la W3C. Usando las APIs nativas que provee el navegador. Como has podido ver, hay bastante código que puede ser algo repetitivo si por ejemplo tenemos varias propiedades a observar.

Este tipo de cosas son las que implementan librerías como Polymer que sobre todo en su versión 2.0 han eliminado muchas cosas para dar mayor protagonismo al soporte nativo del navegador.


Referencias

Si quieres profundizar más sobre ésta nueva tecnología te dejo los siguientes enlaces:

✎ ¿Ves alguna errata? ¿Quieres modificar algo? Haz una Pull Request.

Carlos Azaustre

Soy Carlos Azaustre. Me dedico al desarrollo web. Actualmente trabajo como Senior Frontend Engineer en Eventbrite. Fui nombrado en 2019 GDE (Google Developer Expert) en Tecnologías Web. Desde 2013 intento documentar en éste blog todo lo que aprendo y así compartirlo con el resto de la comunidad.

Si te gusta lo que lees, puedes apoyarme en mi Patreon o invitarme a un café virtual 🙂

Se mi patrón Invítame a un Café