-
Notifications
You must be signed in to change notification settings - Fork 379
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
Is there a way to detect if a custom element was constructed during parsing? #789
Comments
|
In general there is no way to know whether a given element is created by the parser or not. The only thing you can observe is whether an element got upgraded by getting inserted into a document or constructed synchronously. I don't quite understand what the use case for such a detection is, however. |
Thanks guys! Are there any edge cases that How would you recommend polyfilling In my MutationObserver-based childConnected/DisconnectedCallback example I used my own |
When a custom element had been upgraded, then In general, I'd be interested to know what the exact use case is for detecting when a parser is creating a custom element. Some builtin elements do this (e.g. form control, script, etc...) but mostly due to legacy behaviors that is needed for backwards compatibility) Finally, the best way to polyfill isConnected is something like this: if (!Object.getOwnPropertyDescriptor(Node.prototype, 'isConnected')) {
let rootNode = null;
if (Node.prototype.getRootNode)
rootNode = (node) => node.getRootNode({composed: true});
else {
rootNode = (node) => {
for (let ancestor = node, ancestorParent; ancestor; ancestor = ancestorParent) {
ancestorParent = ancestor.parentNode || ancestor.host;
if (!ancestorParent)
return ancestor;
};
return node;
}
}
Object.defineProperty(Node.prototype, 'isConnected', {
get() { return rootNode(this).nodeType == Node.DOCUMENT_NODE; },
enumerable: true,
configurable: true,
});
} |
You can add some kind of caching but then you'd have to invalidate whenever a node is removed / inserted so it's probably not a great trade off. |
Ah, thanks! I suppose we'd also need to patch
I was wondering if it would be helpful in any way for improving the |
No, there is no need to store any host because host is always available regardless of whether the shadow root is closed or open. |
Ah, okay, thanks! For some reason I didn't think that was the case, but just verified that it works. |
Is the "fragment parser" invoked when I do something like document.body.insertAdjacentHTML('beforeend', '...') ? The reason I'm asking is because this other form of parsing seems to work differently than initial-payload parsing, leading me to yet another case that I need to detect: In parsing of the initial HTML payload markup,
However, if I use At least, this is what I'm observing in Chrome. I'm trying to find out exactly what's happening. Seems like the mutation events in the case of parsing due to So now I have two cases to detect: parsing the initial payload, and parsing from The reason I want to detect these things is because in implementing |
yes, |
Ah okay, thanks. I wasn't familiar with the terminology (and google searches weren't very helpful). Can you point me to details regarding "the upgrading path"? |
I mean all the elements get created as a subtree then upgraded later. Just as if you made a subtree then append it via |
It's not quite the same as manual use of And it also isn't the same initial-payload parsing (obviously). Here's the issue, I made two (EDIT: three) fiddles showing the difference between initial-payload parser, and fragment parser (and createElement/appendChild):
Seems like I need to detect the difference between the two parsings (EDIT: or maybe detect case 2 and 3 the same way), and in the second (and third) case I need to manually trigger child-handling logic. |
I'm just saying that the behavior of upgrading is identical to Anyway, I'm going to close this issue. This issue isn't really appropriate for standards discussion. There are no use cases presented, and there doesn't seem to be any API or spec change proposal. |
Hey Ryo, the use case is presented, in the above 2nd fiddle. It's not clear how to detect or work with children in that case, in order to run logic on any/all upgraded children in a guaranteed way like we can with initial-payload parsing in the the 1st fiddle. So as far as specs are concerned, can we modify fragment parser so it behaves like initial-payload parsing? That'd make things consistent, and that issue wouldn't exist. |
Wanting to detect when a custom element is created by a fragment parsing algorithm is NOT a use case. Wanting to have a guarantee that each child has been upgraded before accessing it is NOT a use case. A use case is a specific user scenario.
Like I've stated dozens of times, with the current custom elements API, you'd need to have a child talk to its parent, not a parent finding the right kind of children. |
Anyway, if you wanted to do something with every child custom element in a parent, you'd do something like this. I didn't debug too much but seems to mostly work. <!DOCTYPE html>
<html>
<body>
<custom-parent><div></div><custom-child id="c1"></custom-child><span></span></custom-parent>
<script>
class CustomParentElement extends HTMLElement {
isChildElementToWatch(node) { return node.localName == 'custom-child'; }
constructor() {
super();
const nodesToCheck = [];
for (let node = this.firstChild; node; node = node.nextSibling) {
if (!this.isChildElementToWatch(node))
continue;
if (node.matches(':defined'))
this.didConnectCustomChild(node);
else
nodesToCheck.push(node);
}
Promise.resolve().then(() => {
for (const node of nodesToCheck) {
if (node.matches(':defined'))
this.didConnectCustomChild(node);
}
});
const observer = new MutationObserver((recordList) => {
const addedNodes = new Set;
for (const record of recordList) {
for (const node of record.addedNodes) {
if (this.isChildElementToWatch(node))
addedNodes.add(node);
}
// This skips all the elements that got temporaily inserted and then removed.
// Delete this code if you wanted to observe all children ever got inserted.
for (const node of record.removedNodes) {
if (this.isChildElementToWatch(node))
addedNodes.delete(node);
}
}
for (const node of addedNodes)
this.didConnectCustomChild(node);
});
observer.observe(this, {childList: true});
}
didConnectCustomChild(child) {
console.log(child);
}
}
customElements.define('custom-parent', CustomParentElement);
class CustomChildElement extends HTMLElement { }
customElements.define('custom-child', CustomChildElement);
</script>
<custom-parent><div></div><custom-child id="c2"></custom-child><span></span></custom-parent>
<script>
const parent = document.createElement('custom-parent');
parent.appendChild(document.createElement('custom-child')).id = 'c3';
parent.innerHTML = '<custom-child id="c4"></custom-child>';
</script>
</body>
</html> |
F.e.,
The text was updated successfully, but these errors were encountered: