-
Notifications
You must be signed in to change notification settings - Fork 383
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to wait for will-be custom elements to be upgraded? #558
Comments
I documented a possibly solution in #559, but note I may be incorrect about my assumptions of how the upgrade process works, and I may be experiencing only the sideeffects of the Chrome v0 implementation. |
This is explicitly not the case in v1 API. We would always invoke |
Do
|
whenDefined() is the answer here, indeed. |
@domenic @kojiishi This is currently difficult to work with without using ugly deferral hacks and leaking memory. @rniwa's |
In my experiences so far, I define custom elements, and the
<body>
of the page is empty. At some point in the future after the custom elements are defined and after the document is loaded, I use a view layer (f.e. React, Meteor Blaze, etc) to render some components which results in elements being added into the<body>
. This works really well because by the time my custom elements get placed into the DOM (indirectly, by the view layers, not by me), then the registered Custom Element classes have their life cycle callbacks (I'm on v0, so createdCallback, attachedCallback, detachedCallback, and attributeChangedCallback) fired as expected and in the correct order.It is a completely different story when we're not using a view layer. Suppose we're sending HTML markup from the server. The HTML markup is parsed at some point in time which can possibly before the Custom Element classes are ever registered. What can happen is that when the Custom Element classes are finally registered, the DOM tree may already be created, which causes attachedCallbacks to fire in possibly the incorrect order because if there are multiple custom element classes that should be registered, then what happens is that the
attachedCallback
of one element may be called but not that of the other elements that are not yet upgraded, which causes problems with a framework that defines multiple elements.Another thing is that if Custom Element classes are registered after the elements already exist in DOM, then their
attributeChangedCallback
methods will not be fired with the initially set attribute values (if any). Note, I am testing this with Chrome's native v0 implementation, and that is the behavior that I observe.Let me explain how the problems can be solved by showing you some hacks I've written:
The following is an excerpt from a class, with some code removed for simplicity just to show the problem. What you'll see is that in the
attachedCallback
I've implemented some code that will manually callattributeChangedCallback
in the case that there might be pre-existing attributes on the element once it has been upgraded (Chrome's implementation does not callattributeChangedCallback
in this case). You'll also notice that I've written a polyfill for mychildConnectedCallback
idea, and in the implementation you'll see that I'm usingsetTimeout
, which is an ugly and horrible hack in order to defer some code so that the code can be executed after upgrade ofthis
element's children has been completed, otherwise the callbacks may be executed before the child elements are upgraded (i.e. before the child element classes are registered):Subclasses of the class shown above implement
childConnectedCallback
, and rely on their children being instances of my framework's custom element classes.Again, this all works fine if my classes are registered before any of these elements are ever placed into the DOM. But, if the elements exist prior to registration, they will need to be upgraded, and then my code would not work without the
setTimeout
hack and the manual calling of theattributeChangedCallback
methods.This has led me to ask the following question on stackoverflow: How to wait for Custom Element reference to be “upgraded”?.
I believe if there were some official way to wait for the upgrade of an element if all you have is a reference to that element (without the ability to modify that element's code prior), then it might make it easier to write code in a way that isn't so hacky as in my above example.
It may be possible that an element is never registered, so maybe there would also need to be a way to cancel the waiting for upgrade, in order not to leak memory.
Assume that the custom elements that I will await to be upgraded are third party elements. I don't want to monkey patch the
createdCallback
of the element whose reference I have, as that would also be hacky.Is there any way to do something after an element has been upgraded?
Is there any other recommended approach?
Previously, I simply placed logic into my child elements that on
attachedCallback
would look for their parents in order to create a connection with their parents, but this fails badly with closed shadow trees as described in #527, so I've since changed my API so that it is parents that observe children in order to create connections with the children.However!
The parent cannot create a connection with the children when the parent class is registered and the child class is not yet registered because the parent depends on custom properties existing on the upgraded children, which is why I've written the above hacks. This scenario seems to happen due to the fact that element registration seems to be synchronous.
Suppose we have this code:
The first line will cause
some-el
elements to be upgraded synchrously, and those elements will therefore execute logic immediately, and if that logic depends on child elements beingother-el
, then the logic will fail. However, if I defer the logic, then that gives a chance for the registration ofother-el
to happen first, and then the logic in the parent will succeed.Once again, this is not a problem at all when the elements are registered before any of the elements are ever placed into the DOM. For example, when I use React, then React will "render" my custom elements into the DOM in the future after my custom element classes have already been registered. However, I've also made a "global" version of my library, and in one case I am simply sending the markup from the server (not using a client-side view layer), so what happens is that Chrome's v0
document.registerElement
API seems to upgrade elements after they already exist in the DOM (it will need to upgrade the elements rather than instantiate them from my custom classes).The text was updated successfully, but these errors were encountered: