Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> The real power of HTMX and Web Components is that Web Components self-initialize when they get attached to the DOM,

I've run into some problems with the Custom Element lifecycle, though. Not sure how to solve them, because `connectedCallback` is the wrong place for my custom code. The odds are I am doing it wrong (or have a fundamental misunderstanding!)

Basically, lets say I have two custom elements: A and B.

All Bs are a descendant (even if not direct) of an A.

Each A grabs all B children and copies the data out of a specified child of the B, then uses it.[1]

When the connectedCallback for A is executed, the Bs are not yet connected and thus don't show up in a call to querySelector.

I've (sort of) worked around this by having each B, when connected, find the closest A ancestor, and add itself to an array field of that ancestor. A's connectedCallback performs a setInterval with ever-increasing delays until some specific maximum (I use 10ms). The setInterval just redisplays with whatever labels are in the array.

Now, this is probably a stupid way of doing this, and I believe a better way is to use MutationObserver, which I will probably switch to at some point.

However, my point is still: the life-cycle did not offer me some way to hook into A only when all the children are attached to the DOM.

[1] A practical example of this would be tabbed-containers. The <tab-container> shouldn't hold the labels for each <tab-item>, it should get the labels from the <tab-item> itself.



Another option would be for the B to dispatch a `CustomEvent` on itself. That event will bubble up the DOM until it hits A. A would then need an event listener that would probably stop propagation and do whatever bookkeeping is necessary.


This seems like the best option, because it works just as well if the child components are loaded async (Ie: a tab component loading sub tabs on hover, and then the parent tab container needing to subscribe to that)


I believe this is what whenDefined was made for.

https://developer.mozilla.org/en-US/docs/Web/API/CustomEleme...

It's not been well covered in the standard Custom components blogs.


I think your workaround is probably the most preferable of the options. I've worked with mutation observers a lot and I wouldn't want to rely on them for anything that didn't have a simpler mechanism to achieve the same thing.

In "regular" frameworks, this problem would be expressed as state that is owned by A, that B's contribute to. Maybe by calling a function passed down to them, or by updating a shared store. It's a big shortcoming that composition of web components is limited to string attributes unless you use some sort of framework to mediate things.


I think this is decent approach, although setInterval may be unnecessary. I do this similarily as a base Class, and i made a generic solution that would not allow for A's to be initialized until all of its children registered thsemselves.


slotchange is your answer. In the connectedCallback add the eventListener and inside your slotchange handler: const myBs = this._slot?.assignedElements();




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: