1

<script>
  class SomeClass extends HTMLElement {
    constructor() {
      super();
    }

    connectedCallback() {
      // returns empty nodelist
      console.log(this.querySelectorAll('.thing'));
    }

  }

  customElements.define('my-component', SomeClass);
</script>

<my-component>
  <div class="thing"></div>
  <div class="thing"></div>
  <div class="thing"></div>
</my-component>

When I try to query child elements within connectedCallback, I get an empty nodelist.

If I move script tag after <my-component> - it starts working:

<my-component>
  <div class="thing"></div>
  <div class="thing"></div>
  <div class="thing"></div>
</my-component>

<script>
  class SomeClass extends HTMLElement {
    constructor() {
      super();
    }

    connectedCallback() {
      // returns empty nodelist
      console.log(this.querySelectorAll('.thing'));
    }

  }

  customElements.define('my-component', SomeClass);
</script>

Is there some callback that triggers when all child elements are available? (no matter where <script> was added). Do I really have to use something like document.ready or mutation observer? What's the most efficient way?

Marvin3
  • 5,741
  • 8
  • 37
  • 45
  • This fiddle has the script in the `` and works fine: https://jsfiddle.net/khrismuc/drb97me2/ –  May 04 '19 at 09:40
  • I'm testing this on Firefox. Chrome indeed does things differently. But yeah, the solution is to use a DOM ready event. –  May 04 '19 at 09:46
  • @LGSon how is this a duplicate? it's totally unrelated issue, since when web components require document.ready. – Marvin3 May 04 '19 at 09:51
  • If you try to access an element with a script where the script runs _before_ the elements been parsed/DOM ready, always, hence this being a duplicate, and its answers explains that. – Asons May 04 '19 at 09:53
  • @LGSon that is understandable, but how does your "duplicate" thread answer the question for web components that can be added dynamically any time? – Marvin3 May 04 '19 at 09:56
  • It doesn't, but you don't ask about that, you ask _"When I try to query child elements within connectedCallback, I get an empty nodelist."_, and with the given sample, it is a duplicate. If you need to know about dynamically added components, you need to post a question/sample that does that, though if the logic in such sample is the same as in this, it will as well fail for the same reason. – Asons May 04 '19 at 10:00
  • @LGSon I'm sorry for chosing incorrect title, I edited it. – Marvin3 May 04 '19 at 10:02
  • Found the reason, reopened and posted an answer – Asons May 04 '19 at 10:17
  • 1
    Possible duplicate of [How to have a 'connectedCallback' for when all child custom elements have been connected](https://stackoverflow.com/questions/48663678/how-to-have-a-connectedcallback-for-when-all-child-custom-elements-have-been-c) – Supersharp May 04 '19 at 21:57

1 Answers1

1

There appear to be a different behavior between browsers, where it works on e.g. Firefox, but Chrome (Blink) need "Mutation Observers".


Optionally one can place the script after the component, for the same reason DOM work in general.


Or make the customElements.define() call after DOM been loaded

<script>
  class SomeClass extends HTMLElement {
    constructor() {
      super();
    }

    connectedCallback() {
      // returns empty nodelist
      console.log(this.querySelectorAll('.thing'));
    }

  }

  window.addEventListener('DOMContentLoaded', function() {
    customElements.define('my-component', SomeClass);
  });
</script>

<my-component>
  <div class="thing"></div>
  <div class="thing"></div>
  <div class="thing"></div>
</my-component>
Asons
  • 84,923
  • 12
  • 110
  • 165