Search code examples
javascriptweb-componentlit-element

Why the property 'classList' cannot be read?


I am trying to add and remove a class depending on whether a variable is equal to 0. Here is my code:

import { LitElement, html } from 'lit-element';

class SelectCounter extends LitElement {
static get properties() {
    return {
        numPassengers: {type: Number},
    };
}

constructor() {
    super();
    this.numPassengers = 0;
    this.disableState();
}

createRenderRoot() {
    return this;
}

disableState() {
    this.btn = document.querySelector('.minus');
    if (this.numPassengers === 0) {
        this.btn.classList.add('counter__btn--disable');
    }
}

render(){
    return html`
        <div class="counter">
            <a class="counter__btn minus" href="#"></a>
            <span class="counter__label">${this.numPassengers}</span>
            <a class="counter__btn" href="#"></a>
        </div>
    `;
}
}
customElements.define('select-counter', SelectCounter);

I've tried it in several ways but I don't understand why it happens. Any idea?


Solution

  • You're calling disableState() in the constructor, when the DOM of the component is not ready yet so this:

    this.btn = document.querySelector('.minus');
    

    is null.

    If you move that logic in firstUpdated() then it should work.

    firstUpdated() {
        disableState();
    }
    
    disableState() {
        // Also, consider querySelecting inside this.renderRoot
        // to avoid picking elements with the same class in
        // other parts of the document
        this.btn = this.renderRoot.querySelector('.minus');
        // ...
    }
    

    Note that you can do the same thing in a more declarative way, without the need to select the element:

    render() {
        return html`
            <div class="counter">
                <a class="counter__btn minus ${this.numPassengers === 0 ? 'counter__btn--disable' : ''}" href="#"></a>
                <span class="counter__label">${this.numPassengers}</span>
                <a class="counter__btn" href="#"></a>
            </div>
        `;
    }
    

    or by using lit-html's classMap directive:

    import {classMap} from 'lit-html/directives/class-map.js';
    
    // ...
    
    render() {
        return html`
            <div class="counter">
                <a class=${classMap({
                    counter__btn: true,
                    minus: true,
                    'counter__btn--disable': this.numPassengers === 0,
                })} href="#"></a>
                <span class="counter__label">${this.numPassengers}</span>
                <a class="counter__btn" href="#"></a>
            </div>
        `;
    }