最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - attributeChangedCallback doesn't get called even after defining observedAttributes - Stack Overflow

programmeradmin6浏览0评论

In the following code, attributeChangedCallback never gets called even if the 'content' attribute is created, changed or removed.

class Square extends HTMLElement {

    static get observedAttributes() {

        return ['content'];
    }
    constructor(val) {
        super();
        console.log('inside constructor');
        this.attachShadow({mode: 'open'});
        this.shadowRoot.appendChild(document.createElement('button'));

        this.button = this.shadowRoot.querySelector('button');
        this.button.className = "square";

        this.content = val;

        console.log('constructor ended');
    }

    get content() {
        console.log('inside getter');
        return this.button.getAttribute('content');
    }
    set content(val) {
        console.log('setter being executed, val being: ', val);
        // pass null to represent empty square
        if (val !== null) {
            this.button.setAttribute('content', val);

        } else {
            if (this.button.hasAttribute('content')) {
                this.button.removeAttribute('content');
            }
        }

    }
    connectedCallback() {
        //console.log('connected callback being executed now');
    }

    // not working :(
    attributeChangedCallback(name, oldValue, newValue) {
        console.log('attribute changed callback being executed now');
        if (name === 'content') {
            this.button.innerHTML = newValue?newValue:" ";
        }
    }
}
customElements.define('square-box', Square); 

Based on the best practices given here, I want the side-effect of attribute change (updation of innerHTML in my case) to take place in attributeChangedCallback. However when I move this updation to the setter, the code works fine.

In the following code, attributeChangedCallback never gets called even if the 'content' attribute is created, changed or removed.

class Square extends HTMLElement {

    static get observedAttributes() {

        return ['content'];
    }
    constructor(val) {
        super();
        console.log('inside constructor');
        this.attachShadow({mode: 'open'});
        this.shadowRoot.appendChild(document.createElement('button'));

        this.button = this.shadowRoot.querySelector('button');
        this.button.className = "square";

        this.content = val;

        console.log('constructor ended');
    }

    get content() {
        console.log('inside getter');
        return this.button.getAttribute('content');
    }
    set content(val) {
        console.log('setter being executed, val being: ', val);
        // pass null to represent empty square
        if (val !== null) {
            this.button.setAttribute('content', val);

        } else {
            if (this.button.hasAttribute('content')) {
                this.button.removeAttribute('content');
            }
        }

    }
    connectedCallback() {
        //console.log('connected callback being executed now');
    }

    // not working :(
    attributeChangedCallback(name, oldValue, newValue) {
        console.log('attribute changed callback being executed now');
        if (name === 'content') {
            this.button.innerHTML = newValue?newValue:" ";
        }
    }
}
customElements.define('square-box', Square); 

Based on the best practices given here, I want the side-effect of attribute change (updation of innerHTML in my case) to take place in attributeChangedCallback. However when I move this updation to the setter, the code works fine.

Share Improve this question asked Feb 20, 2020 at 11:59 user103643user103643 431 gold badge1 silver badge3 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 4
set content(val) {
        console.log('setter being executed, val being: ', val);
        // pass null to represent empty square
        if (val !== null) {
            this.button.setAttribute('content', val);

        } else {
            if (this.button.hasAttribute('content')) {
                this.button.removeAttribute('content');
            }
        }

    }

You are mixing up parents & children

You are defining a setter on your Element <square-box> (►parent element)

When you do this.button.setAttribute('content', val);

You are changing a attribute of your <button> Element (►child element)

This will never trigger the attributeChangedCallback of (►parent) <square-box>
because its attributes were not changed

You either have to go "up the DOM" with .getRootNode() and/or .host to set attributes of parent elements.

or use Custom Events (bubbling up the DOM) to notify parents that children have done/changed something

I presume you meant to do

set content(val) {
        //  loose ==null parison for null AND undefined, 
        //  element.content=null; will remove the attribute
        if (val==null) 
            this.removeAttribute('content');
        else 
        //  but you DO want .content(0) (0==false) set as "0"
            this.setAttribute('content', val);
    }

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论