Company logo
  • Empleos
  • Bootcamp
  • Acerca de nosotros
  • Para profesionales
    • Inicio
    • Empleos
    • Cursos y retos
    • Preguntas
    • Profesores
    • Bootcamp
  • Para empresas
    • Inicio
    • Nuestro proceso
    • Planes
    • Pruebas
    • Nómina
    • Blog
    • Calculadora

0

68
Vistas
Cloned Custom HTML Element does not become custom element until it's attached to the main DOM?

Consider the following scenario where I have a list of custom elements which is dynamically created. The CustomElement has a custom property displayName that should do something when set:

class CustomElement extends HTMLElement {
  set displayName(v) {
    this.querySelector(".name").textContent = v;
  }
}
customElements.define("custom-element", CustomElement)

const template = document.querySelector("template");
const list = document.querySelector(".list");
document.querySelector("button").addEventListener("click", () => {
  const customElTemplate = template.content.firstElementChild;
  console.log("Template constructor: ", customElTemplate.constructor.name);

  const el = template.content.firstElementChild.cloneNode(true);
  console.log("Cloned el constructor:", el.constructor.name);
  
  el.displayName = "Should has content";
  
  const frag = new DocumentFragment();
  frag.appendChild(el);
  console.log("Cloned el in DocumentFragment constructor:", el.constructor.name);
  
  list.appendChild(frag);
  console.log("Cloned el in Document constructor:", el.constructor.name);
});
custom-element {
  display: block;
  margin-bottom: .5rem;
  border: 1px solid black;
}
<template>
  <custom-element><span class="name"></span></custom-element>
</template>

<button>Add Item</button>

<div class="list"></div>

When clicking the button, the console output are:

Template constructor:  HTMLElement
Cloned el constructor: HTMLElement
Cloned el in DocumentFragment constructor: HTMLElement
Cloned el in Document constructor: CustomElement

As you can see, the cloned element doesn't become CustomElement until it's attached to the root document and displayName is simply a plain property that does nothing.

el.displayName = "Should has content"; won't work even after attaching to a DocumentFragment. It only works after attaching to the document (i.e. after list.appendChild(frag); in the above example)

Why is this happening? Is there anyway I can set up the element before attaching it to the main document?

UPDATE: I see there is customElements.upgrade, but even adding it, nothing is changed, unlike the example provided in the article:

customElements.upgrade(el);
7 months ago · Juan Pablo Isaza
1 Respuestas
Responde la pregunta

0

I found out about customElements.upgrade. Turned out I have to call it after attaching to a shadow DOM:

frag.appendChild(el);
customElements.upgrade(el);

// Now el is CustomElement
console.log(el.constructor.name);

The upgrade() method of the CustomElementRegistry interface upgrades all shadow-containing custom elements in a Node subtree, even before they are connected to the main document.

For the example in my question, I need to:

  • Attach it to a DocumentFragment,

  • Call customElements.upgrade

  • Now I can use custom behavior like setting displayName.

Working code:

class CustomElement extends HTMLElement {
  set displayName(v) {
    this.querySelector(".name").textContent = v;
  }
}
customElements.define("custom-element", CustomElement)

const template = document.querySelector("template");
const list = document.querySelector(".list");
document.querySelector("button").addEventListener("click", () => {
  const customElTemplate = template.content.firstElementChild;
  console.log("Template constructor: ", customElTemplate.constructor.name);

  const el = template.content.firstElementChild.cloneNode(true);
  console.log("Cloned el constructor:", el.constructor.name);
  
  const frag = new DocumentFragment();
  frag.appendChild(el);
  customElements.upgrade(el);
  console.log("Cloned el in DocumentFragment constructor:", el.constructor.name);
  
  el.displayName = "Should has content";
  
  list.appendChild(frag);
  console.log("Cloned el in Document constructor:", el.constructor.name);
});
custom-element {
  display: block;
  margin-bottom: .5rem;
  border: 1px solid black;
}
<template>
  <custom-element><span class="name"></span></custom-element>
</template>

<button>Add Item</button>

<div class="list"></div>

7 months ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar empleo Planes Nuestro proceso Comercial
Legal
Términos y condiciones Política de privacidad
© 2023 PeakU Inc. All Rights Reserved.