I am trying to understand the newish HTML custom elements.
My goal is, given some array of data, create n instances of the custom element. For example, given a list of 10 users, create 10 user html objects.
Ok - so I define a custom element in the html
HTML
<template-user>
   <div class="user-name"></div>
</template-user>
Then I create my controller
JS
class UserTemplate extends HTMLElement {
   constructor(){
      super();
      this.username = this.querySelectorAll('[class="user-name"]')[0];
   }
   setName(name){
      this.username.innerHtml = name;
   }
}
customElements.define('template-user', UserTemplate);
The page loads fine, but now I am confused on how to reuse that element. If I was doing normal old school stuff, I'd have a for-loop pumping out some HTML strings and setting the innerHTML of something. But now I'd rather do something like
for(let i = 0; i < users.length; i++){
   let userTemplate = new UserTemplate();
   userTemplate.setName(user.name);
   // append to user list, etc..
}
When I try to do this, it seems to almost work. But it cannot find username, ie this.querySelectorAll will return null. That's only when I try to construct a new instance of this element. How then, am I supposed to create new custom element DOM objects?
We can create custom HTML elements, described by our class, with its own methods and properties, events and so on. Once a custom element is defined, we can use it on par with built-in HTML elements.
The bread and butter of Web Components are custom elements. The customElements API gives us a path to define custom HTML tags that can be used in any document that contains the defining class. Think of it like a React or Angular component (e.g. ), but without the React or Angular dependency.
There are two types of custom elements: Autonomous custom elements are standalone — they don't inherit from standard HTML elements. You use these on a page by literally writing them out as an HTML element. For example <popup-info>, or document.createElement ("popup-info"). Customized built-in elements inherit from basic HTML elements.
We can extend and customize built-in HTML elements by inheriting from their classes. For example, buttons are instances of HTMLButtonElement, let’s build upon it. Provide the third argument to customElements.define, that specifies the tag:
Make sure you understand the requirements and limitations of constructors for Web Components:
https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-conformance
4.13.2 Requirements for custom element constructors
When authoring custom element constructors, authors are bound by the following conformance requirements:
Several of these requirements are checked during element creation, either directly or indirectly, and failing to follow them will result in a custom element that cannot be instantiated by the parser or DOM APIs. This is true even if the work is done inside a constructor-initiated microtask, as a microtask checkpoint can occur immediately after construction.
You could make changes similar to this:
class TemplateUser extends HTMLElement {
  static get observedAttributes() {
    return ['user-name'];
  }
  constructor(){
    super();
    this.attachShadow({mode:'open'});
    this.shadowRoot.innerHTML = '<div></div>';
  }
   
  attributeChangedCallback(attrName, oldVal, newVal) {
    if (oldVal !== newVal) {
      this.shadowRoot.firstChild.innerHTML = newVal;
    }
  }
 
  get userName() {
    return this.getAttribute('user-name');
  }
  
  set userName(name) {
    this.setAttribute('user-name', name);
  }
}
customElements.define('template-user', TemplateUser);
setTimeout( function () {
  var el = document.querySelector('[user-name="Mummy"]');
  el.userName = "Creature from the Black Lagoon";
}, 2000);
<template-user user-name="Frank N Stein"></template-user>
<template-user user-name="Dracula"></template-user>
<template-user user-name="Mummy"></template-user>
This uses shadowDOM to store a <div>, then you set the value through the user-name attribute or through the userName property.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With