Search code examples
templatesweb-component

QuerySelector not working after fetching template - WebComponents


The TeleMenu is having two buttons and I'm trying to grab them, but there is a problem with this.shadowRoot.querySelector.

Error:

Uncaught (in promise) TypeError: Cannot read property 'querySelector' of null

Code:

class TeleMenu extends HTMLElement {

buttons = [];

constructor() {
    super();

    fetch('tele-menu.html')
        .then(resp => resp.text())
        .then(resp => {
            this.attachShadow({ mode: 'open' })
                .innerHTML = resp
        })

    this.buttons = Array.from(this.shadowRoot.querySelectorAll('button'));
}

Can you help?

Thanks


Solution

  • fetch is asynchronous, you are executing .querySelectorAll long before the innerHTML is set

    constructor() {
        super();
    
        fetch('tele-menu.html')
            .then(resp => resp.text())
            .then(resp => {
                this.attachShadow({ mode: 'open' })
                    .innerHTML = resp
            })
    
        this.buttons = Array.from(this.shadowRoot.querySelectorAll('button'));
    }
    

    The Google and MDN documentation is wrong with run super() first

    super() sets and creates the 'this' scope.

    So you can't call this before super has run.. that's the only limitation

    You can do:

    constructor() {
        fetch('tele-menu.html')
            .then(resp => resp.text())
            .then(resp => {
                super().attachShadow({ mode: 'open' })
                       .innerHTML = resp;
                this.buttons = [...this.shadowRoot.querySelectorAll('button')];//modern way
                // do more here
            })
    }
    

    https://javascript.info/async-await probably helps in keeping your code cleaner