I am making a web component with vanilla JavaScript as follows:
<template id="TEMPLATE_UPLOADER">
<div>Try Query Me</div>
</template>
<script>
customElements.define('my-uploader', class extends HTMLElement {
constructor() {
const template = document.getElementById("TEMPLATE_UPLOADER");
const content = template.content;
let superThis = super() // Create and binds the this keyword
let shadowRoot = superThis.attachShadow({mode: "open"});
shadowRoot.appendChild(template.cloneNode(content, true));
}
/** Custom Component Reactions **/
connectedCallback() {
setTimeout(this.init.bind(this), 1000)
}
init() {
const el = this.shadowRoot.querySelector('div');
console.log('I hope el is not null:', el)
}
});
</script>
<my-uploader></my-uploader>
Now within init()
I wish to query some of elements within the template for this component. However this.shadowRoot.querySelector
always returns null
. I red that the elements are not yet created at connectedCallback
time, so I set a timeout to call init()
after 1 second to ensure it was finished being created, but got the same result. This is what this.shadowRoot
looks like in Chrome (side note this
is <my-uploader></my-uploader>
):
As you can see there are divs
inside, however this.shadowRoot.querySelector('div')
returns null. How to query items within the web component?
template.cloneNode(content, true)
Should be: template.cloneNode(true)
Your content
is a DOM reference interpreted FALSE, thus you created a SHALLOW copy, without the <div>
I condensed your code a bit
<template id="TEMPLATE_UPLOADER">
<div>Try Query Me</div>
</template>
<script>
customElements.define('my-uploader', class extends HTMLElement {
constructor() {
const template = document.getElementById("TEMPLATE_UPLOADER").content;
super()
.attachShadow({mode: "open"})
.append(template.cloneNode(true));
}
connectedCallback() {
setTimeout( () => this.init() ); // don't learn JRs that oldskool bind stuff
}
init() {
const el = this.shadowRoot.querySelector('div');
console.log('I hope el is not null:', el)
}
});
</script>
<my-uploader></my-uploader>