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 Componentsell-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:
Y después, tras cambiar el valor de text
por el texto: "Lo quiero ahora!" tendríamos esto:
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 dewebcomponents
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:
Y si hacemos como con el ejemplo anterior, una función de timeout que cambie las propiedades pasados 2 segundos, tendremos el nuevo resultado:
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: