Search code examples
javascriptweb-componentnative-web-component

Create a BaseComponent for web components, and refer to component name once


I have noticed there are a few common/repeated methods I keep reusing in some web components I am working on. When I change the method in one, if I want the improvement in the others, I have to open each one and make the changes to all the other components, which is tedious and error prone. So I am trying to create a BaseComponent which the other components inherit from.

The issue is I would like to define the component name, e.g. wc-thingy in one place, keep it DRY. However this name is requried in two places:

  1. To find the template of the component (I name the id of the template TEMPLATE_<component_name>, e.g. TEMPLATE_wc-thingy
  2. To customElements.define it.

Below is my attempt to try accomplish it, but I think the issue is this.constructor is not refering to the subclass class instance:

window.BaseComponent = class extends HTMLElement {
    static componentName;

    static define(componentName) {
        this.constructor.componentName = componentName;
        window.customElements.define(this.constructor.componentName, this);
    }

    constructor() {
        super();
        this.attachShadow({ mode: "open" });
        const template = document.getElementById("TEMPLATE_" + this.constructor.componentName);
        this.shadowRoot.appendChild(template.content.cloneNode(true));
        console.log("Contructed", this.constructor.componentName)
    }

    sayHello() {
        console.log("Hello");
    }
};

(class extends window.BaseComponent {
    sayBi() {
        console.log("K Bi, thxns!");
    }
}).define('wc-thingy')
<wc-thingy>thingy here</wc-thingy>


Solution

  • +1 for creating your own BaseComponent

    -392.176.112 if you now think you are great, and sell it to the world like the other 60+ BaseClasses

    The Web Component name is in this.nodeName (uppercase) or this.localName (lowercase)

    <template id="WC-FOO">foo:<slot></slot></template>
    <template id="WC-BAR">bar:<slot></slot></template>
    
    <wc-foo>FOO</wc-foo>
    <wc-bar>BAR</wc-bar>
    
    <script>
      class BaseComponent extends HTMLElement {
        constructor() {
          const template = () => document.getElementById(this.nodeName).content;
          super().attachShadow({mode:"open"})
                 .append(template().cloneNode(true));
          console.log("Contructed", this.nodeName , this.localName)
        }
      };
      customElements.define("wc-foo", class extends BaseComponent {});
      customElements.define("wc-bar", class extends BaseComponent {});
    </script>