I have a Custom Element
that should have many HTML children. I had this problem when initializing it in class' constructor
(The result must not have children). I understand why and know how to fix it. But exactly how I should design my class around it now? Please consider this code:
class MyElement extends HTMLElement {
constructor() {
super();
}
// Due to the problem, these codes that should be in constructor are moved here
connectedCallback() {
// Should have check for first time connection as well but ommited here for brevity
this.innerHTML = `<a></a><div></div>`;
this.a = this.querySelector("a");
this.div = this.querySelector("div");
}
set myText(v) {
this.a.textContent = v;
}
set url(v) {
this.a.href = v;
}
}
customElements.define("my-el", MyElement);
const frag = new DocumentFragment();
const el = document.createElement("my-el");
frag.append(el); // connectedCallback is not called yet since it's not technically connected to the document.
el.myText = "abc"; // Now this wouldn't work because connectedCallback isn't called
el.url = "https://www.example.com/";
Since MyElement
would be used in a list, it's set up beforehand and inserted into a DocumentFragment
. How do you handle this?
Currently I am keeping a list of pre-connected properties and set them when it's actually connected but I can't imagine this to be a good solution. I also thought of another solution: have an (well I just realized nothing prevents you from invoking init
methodconnectedCallback
yourself) that must be manually called before doing anything but I myself haven't seen any component that needs to do that and it's similar to the upgrade
weakness mentioned in the above article:
The element's attributes and children must not be inspected, as in the non-upgrade case none will be present, and relying on upgrades makes the element less usable.