Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access class function in Web Component from inline Element

I want to execute a defined class function from an Element inside my Web Component:

customElements.define('first-component', class FirstComponent extends HTMLElement {
    constructor() {
        super();
     }

     log() {
        console.log('Well Done!')
     }

     connectedCallback() {
        this.innerHTML = '<button onclick="log()">Do it</button>'
     }
});

State right now: ReferenceError: log is not defined

like image 401
Fabian Avatar asked Jan 02 '23 11:01

Fabian


2 Answers

With parentElement, or closest()

In order to call the log() method of the custom element, you'll have to get a reference on it.

In your example, the custom element is the parent element of the <button> element, so you should call the parentElement property of the button as already stated by @Smankusors:

<button onclick="this.parentElement.log()>Do it</button>

With getRootNode()

Alternately, in a more complex DOM tree, and if a Shadow DOM is used, you can use getRootNode() combined with host to get the custom element reference.

customElements.define('first-component', class FirstComponent extends HTMLElement {
     log() {
        console.log('Well Done!')
     }

     connectedCallback() {
        this.attachShadow({mode: 'open'})
            .innerHTML = '<button onclick="this.getRootNode().host.log()">Do it</button>'
     }
})
<first-component></first-component>

With a unique identifier

You can also call the custom element by its id property (if it has one) :

customElements.define('first-component', class FirstComponent extends HTMLElement {
     log() {
        console.log('Well Done!')
     }

     connectedCallback() {
        if (!this.id)
            this.id = "_id"
        this.innerHTML = `<button onclick="${this.id}.log()">Do it</button>`
     }
})
<first-component></first-component>

With handleEvent()

For security reasons, you can avoid inline script and implement the handleEvent() method, then call inside it a specific method depending on some criterions :

customElements.define('first-component', class FirstComponent extends HTMLElement {
    log() {
        console.log('Well Done!')
    }
     
    handleEvent(ev) {
        if (ev.target.innerText == 'Do it')
            this.log()
    }

    connectedCallback() {
        this.innerHTML = '<button>Do it</button>'
        this.addEventListener('click', this)
    }
})
<first-component></first-component>
like image 133
Supersharp Avatar answered Jan 04 '23 04:01

Supersharp


That shouldn't be log(), but this.log(), because that log function scope is only that element, not in window scope, so your code should be

customElements.define('first-component', class FirstComponent extends HTMLElement {
    constructor() {
        super();
     }

     log() {
        console.log('Well Done!')
     }

     connectedCallback()
        this.innerHTML = '<button onclick="this.parentElement.log()">Do it</button>'
     }
});

-- EDIT -- Sorry, my mistake, I just saw that you added button inside custom element, well... It should be this.parentElement.log() if you still want to prefer inline

like image 40
Smankusors Avatar answered Jan 04 '23 05:01

Smankusors