6

I have a custom element <my-el> structurally similar to this (purely static, server-rendered HTML):

<my-el>
  <div>a</div>
  <div>b</div>
  <div>c</div>
  <div>d</div>
</my-el>

Since Chrome does not guarantee child element availability in the connectedCallback of custom elements, I'm using HTMLParsedElement which basically delays custom element initialization using the following steps:

  1. Test if the element (or any ancestor element) has a nextSibling (in which case the parser assumably has passed my-el), or if DOMContentLoaded has been reached (a.k.a. document.readyState !== 'loading').
  2. If none of the above, set up a MutationObserver on the childList that re-checks the above conditions.

The problem that currently remains with the outlined strategy is that the MutationObserver might get fired when this is the HTML available:

<my-el>
  <div>a</div>
  <div>b</div>
</my-el>

Or even this

<my-el>
  <div>a</div>
</my-el>

In those cases the MutationObserver gets fired several times, and the handler cannot know when the end of </my-el> is actually reached.

Question: Does anyone know if wrapping all the inner div elements like this would solve this problem:

<my-el>
  <div>
    <div>a</div>
    <div>b</div>
    <div>c</div>
    <div>d</div>
  </div>
</my-el>

Or in other words, when the mutation observer fires for this structure, can I reliably assume the wrapping child div being fully available including all its descendant nodes?

connexo
  • 53,704
  • 14
  • 91
  • 128
  • What are your mutationobserver `observerOptions` set to, that may or may not affect you, and also what element are you watching? – Get Off My Lawn Dec 10 '18 at 16:50
  • The element being watched is of course `my-el`, and the options we've been using so far have been `childList: true, subtree: true`. – connexo Dec 10 '18 at 16:52
  • With `subtree: true`, I believe you will get the same effect as you are without the divs being a child of the div – Get Off My Lawn Dec 10 '18 at 16:55
  • 1
    For reasons I don't understand, the author of `HTMLParsedElement` has decided to set up the mutation observer on the `parentNode` of the custom element: `observer.observe(self.parentNode, {childList: true, subtree: true});` https://github.com/WebReflection/html-parsed-element/blob/master/index.js#L59 – connexo Dec 10 '18 at 17:10
  • Last time I checked, the specification didn't say anything about the connection between timing and completeness of the DOM tree. In my experience with MO, parsing of HTML is unpredictable in this regard or rather implementation-dependent. For example, it makes sense for the parser to accumulate the mutation records and prefer to invoke the MO callback when the parsing is paused due to a network request or a mandatory task in JS land like an inline script. You can probably use debounce here. – wOxxOm Dec 10 '18 at 17:12
  • Using `debounce` was my first thought, too, but then again it a) feels extremely dirty and b) that might delay component initialization until after `DOMContentLoaded` (which is very undesirable for consumers of your web components wishing to customize behaviour from the outside (e.g. add their own listeners etc)). But even if I were to try that, how long would you set the debounce period? 1ms? 10ms? And even if you go with 30ms, who tells you there's not going to be another MO trigger after 33ms? – connexo Dec 10 '18 at 17:41
  • 2
    It's worth noting that the test "element or ancestor has a next sibling = element is fully parsed" is not necessarily true. It's similar to this pattern - https://stackoverflow.com/questions/14409982/#14410368 - where an earlier script in the same subtree appends an element to, say, the body element. – Alohci Dec 10 '18 at 23:15
  • @Alohci Thanks for pointing out, but luckily I'm only interested in the nodes that were already there when the HTML was initially delivered, not in dynamically added nodes. – connexo Dec 11 '18 at 07:33

0 Answers0