Search code examples
javascriptweb-component

Event when web component has loaded


I have a web component like this

<template id="component">
    <link href="/static/css/main.cacbacc7.css" rel="stylesheet">
    <script src="/static/js/vendor.js" type="text/javascript"></script>
    <script src="/static/js/bundle.js" type="text/javascript"></script>
    <span id="react-app"></span>
</template>

<script>
  (function (window, document) {
    const doc = (document._currentScript || document.currentScript).ownerDocument;
    const proto = Object.create(HTMLElement.prototype, {
      attachedCallback: {
        value: function () {
          const template = doc.querySelector('template#component').content;
          const shadowRoot = this.attachShadow({ mode: 'open' });
          shadowRoot.appendChild(template.cloneNode(true));
          // executeThis() when all scripts have been loaded
        }
      },
    });
    document.registerElement('react-webcomponent', { prototype: proto });
  })(window, document);
</script>

Can I know when all script tags in my template have been loaded?

Update

What I am currently doing is

const scripts = [...shadowRoot.querySelectorAll('script')];
let scriptsLoaded = 0;
scripts.forEach(function (script) {
  script.addEventListener('load', function () {
    if (++scriptsLoaded >= scripts.length) {
      LoadReactAppIntoShadowDomContainer(shadowRoot.querySelector('#react-app'));
    }
  })
});

But I am hoping for a nicer way.

About the possible duplicate: Will it work for web components?


Solution

  • From what I understand, as of now,

    • you do not have event listeners for onload of the dom in your shadow root

    • when you define a custom element, you can have a connectedCallback which is called when you attach an element to your DOM

    from what you are trying, it seems to me, that you are trying to ascertain, the exact time when your shadow DOM loads its internal scripts

    from what I know, scripts are not scoped to your element, and are global.

    So Instead of trying to do what you are doing at the moment which is,

    • querying the shadow Root's DOM structure, collecting the script tags and attaching an onload,

    you can simply slap an onload to the tags which work like they always have.

    Further, you might be interested in mutation observers if you may want to observe for changes to your shadow DOM, once it is attached and beyond.

    AFAIK, you can not observe DOM changes while you are constructing your element itself / before it is attached

    Or, if you are defining your elements in a different file and prefer using HTML Imports to import them onto the document,

    you can use the webcomponentsready listener from the document that imports, which fires when all the DOM is imported, parsed, and loaded

    If there is indeed a way to observe the DOM or listen to template attachments to your element, I would also like to know.

    Also, Since you are trying to embed your react app into the custom element, which is probably why you had this question of knowing when to call the loadreactapp function, you may want to consider using slots in your shadow DOM, which open up places where you may distribute content after your element has been registered on the browser

    Just add your apps or other custom elements, by passing in the attribute slot=<slotname>