Atributos en WebComponents

Paso de información a WebComponents


Por norma general, los atributos de una etiqueta HTML se utilizan para pasar información desde el exterior a la propia etiqueta HTML. En el caso de los custom elements sirve para exactamente lo mismo. Esta información puede ser de tipo textual o simplemente no tener valor y ser un , que se utiliza para indicar alguna característica verdadera o falsa.

Por ejemplo, observemos el siguiente ejemplo:

<app-element value="15" is-enabled></app-element>

En este caso, el componente tiene 2 atributos:

  • El atributo value contiene el 15, sin embargo, en HTML los atributos siempre son .
  • El atributo is-enabled no indica ningún valor, técnicamente es un de tamaño 0, que se considera un .

Atributo vs Propiedad

Antes de continuar, es importante tener claro un concepto que suele complicarse porque los frameworks Javascript lo ocultan y simplifican. Un atributo HTML y una propiedad Javascript pueden tener el mismo valor, pero no tienen necesariamente que ser iguales.

Veamos un ejemplo para comprenderlo bien. En la clase Javascript asignamos un valor a this.name, por lo que la propiedad name de la clase AppElement valdrá ManzDev:

class AppElement extends HTMLElement {
  constructor() {
    super();
    this.name = "ManzDev";
    console.log("✅ Propiedad: ", this.name);
    console.log("✅ Atributo: ", this.getAttribute("name"));
  }
}
customElements.define("app-element", AppElement);
<p>Mira la consola Javascript para ver el resultado.</p>
<app-element name="Manz"></app-element>

Sin embargo, en la parte del HTML, creamos un elemento HTML <app-element> con el atributo name a Manz. Si pulsamos en la demo y comprobamos la consola Javascript del navegador, veremos que el atributo name tiene el valor Manz, mientras que la propiedad name tiene el valor ManzDev.

Esto ocurre así porque son conceptos diferentes, sin embargo, en los frameworks Javascript los suelen igualar para hacerlo más sencillo.

Ten en cuenta que existen ciertos atributos especiales, como el id, que al establecer dicho atributo, automáticamente se crea su propiedad (y viceversa). No obstante, son excepciones.

Acceder a atributos HTML

Para trabajar con los atributos de un elemento HTML estándar, tenemos los siguientes métodos (los cuales podemos utilizar también para custom elements):

Métodos Descripción
this.hasAttributes() Nos indica si el componente tiene algún atributo.
this.getAttributeNames() Devuelve un de atributos (lowercase).
this.hasAttribute(name) Nos indica si el atributo name está definido.
this.getAttribute(name) Devuelve el valor del atributo name o si no existe.

Algunas consideraciones interesantes:

  • El método getAttributeNames() devuelve un array con todos los atributos del elemento. Los strings están siempre en minúsculas (lowercase).

  • El método .getAttribute() devuelve cuando no existe el atributo indicado. Si existe pero no tiene valor, devuelve una cadena de texto vacía.

Todos son métodos que permiten comprobar si existen ciertos atributos o el valor que contienen, así que, veamos como utilizar estos métodos en una clase de un WebComponent.

Observa que los ejecutamos en en el interior del método constructor() y hacemos referencia siempre al this, que es una referencia al componente en cuestión:

class AppElement extends HTMLElement {
  constructor() {
    super();
    console.log("¿Tiene atributos?: ", this.hasAttributes()); // true
    console.log("Número de atributos: ", this.getAttributeNames().length); // 2
    console.log("Atributos: ", this.getAttributeNames()); // ["name", "devname"]
    console.log("¿Existe name?: ", this.hasAttribute("name")); // true
    console.log("Valor de name: ", this.getAttribute("name")); // Manz
    console.log("Atributos inexistentes: ", this.getAttribute("uhghae")); // null
  }
}
customElements.define("app-element", AppElement);
<p>Mira la consola Javascript para ver el resultado.</p>
<app-element name="Manz" devname="ManzDev"></app-element>

Esto es muy interesante para enviar información desde fuera del componente y reutilizarla dentro del componente de forma abstracta. Por ejemplo, en el siguiente fragmento de código obtenemos el atributo name con this.getAttribute() y mediante el operador ?? indicamos un nombre en el caso de que no se añada el atributo al custom element:

const DEFAULT_NAME = "Nombre desconocido";

class AppElement extends HTMLElement {
  constructor() {
    super();
    this.name = this.getAttribute("name") ?? DEFAULT_NAME;
    this.innerHTML = /* html */`
      <div class="card">
        <h1>${this.name}</h1>
      </div>
    `;
  }
}

customElements.define("app-element", AppElement);
<app-element name="ManzDev"></app-element>
<app-element name="MiduDev"></app-element>
<app-element name="MoureDev"></app-element>
<app-element></app-element>

Esta información es guardada en una propiedad del objeto Javascript, concretamente en this.name. Un poco más abajo, observa que con ${this.name} añadimos dicha información en el HTML.

Ten mucho cuidado con aceptar información desde fuera del componente, ya que un usuario podría añadir información maliciosa que se terminaría inyectando en el HTML.

Modificación de atributos HTML

Hasta ahora hemos visto como obtener la información que existe en los atributos HTML. Sin embargo, también podemos modificarlos desde el componente. Para ello, podemos utilizar los siguientes métodos:

Métodos Descripción
this.removeAttribute(name) Elimina el atributo name.
this.setAttribute(name,value) Añade el atributo name al valor value.
this.toggleAttribute(name,force) Si existe, lo elimina, si no existe, lo añade.

Algunas consideraciones interesantes:

  • El método .setAttribute() establecerá el atributo con el valor como , aunque se le pasen otros tipos. Si el valor establecido es una cadena vacía, se añade como .

  • El método .toggleAttribute() añade un atributo si no existía previamente, o lo elimina si ya existía previamente. Si añadimos el segundo parámetro force , simplemente forzaremos a añadir o eliminar el atributo, sin tener en cuenta su estado previo. Este método devuelve si el atributo, tras las operaciones realizadas, existe o no.

En nuestra clase, podemos usar estos métodos para trabajar y modificar estos atributos HTML:

class AppElement extends HTMLElement {
  constructor() {
    super();
    this.setAttribute("name", "ManzDev");
    this.innerHTML = /* html */`
      <div class="data">
        <h1>${this.getAttribute("name")}</h1>
      </div>
    `;
  }
}

En este caso, estamos sobreescribiendo siempre el atributo name con el valor ManzDev, por lo que, independientemente de la información que se envíe por atributo HTML, siempre utilizará ManzDev.

Aquí tienes más información sobre los métodos para gestionar los atributos HTML en el DOM.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev