Event when web component has loaded

Viewed 8082

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?

2 Answers

Your update example is the best way I know of.

I had a similar issue looking to prevent FOUC on my components that were importing CSS via tags.

The only solution I could find is as per your update. QS the ShadowRoot to find the <link> or <scripts>, add a load event listener to each and compare the load count.

The one optimisation you might consider, is when the count matches you can dispatch your own custom load event from the shadow root itself, that a listener on your component shadow root (or further up the tree) can handle.

var event = new CustomEvent('load');
shadowRoot.dispatchEvent(event);

If you want it to bubble up and cross the shadow boundary you'll need to add composed : true to the event args.

var event = new CustomEvent('load', {bubbles : true, composed : true});
shadowRoot.dispatchEvent(event);
Related