Rishav Sharan
Rishav Sharan

Reputation: 2932

How to make function calls with ES6 template literals

UPDATE: Here is a better example; My code is

let myFunction = () => {

    console.log('Yo');
    alert('Yo');

}

let About = {

    render : async () => {

        return /*html*/`
        <h1> About </h1>
        <button id="myBtn" type="button" >Try it</button> 

        <script>
            document.getElementById("myBtn").addEventListener ("click",  ${myFunction})
        </script>
    `
    }
}

export default About;

This transforms to the HTML code;

<div id="page_container" class="container pageEntry">
        <h1> About </h1>
        <button id="myBtn" type="button">Try it</button> 

        <script>
            document.getElementById("myBtn").addEventListener ("click",  () => {

    console.log('Yo');
    alert('Yo');

})
        </script>
    </div>

However on clicking on the button, nothing happens;


I am trying to work on a basic vanilla js SPA and I have hit a problem where I am unable to call any functions in my current module from the html code. I am using the es6 modules by specifying in my index.html that script tag is of type="module".

For example, in this code, i have tried both the inline onclick tag attribute as well as adding an event listener (i used one at a time, not together. showing it here just for illustration)

let myFunction = () => {
    console.log('Yo');
    alert('Yo');
}

let About = {

    render : async () => {

        return /*html*/`
        <h1> About </h1>
        <button id="myBtn" type="button" onclick="${myFunction}">Try it</button> 

        <script>
        document.getElementById("myBtn").addEventListener ("click",  myFunction()})
        </script>
    `
    }
}

export default About;

and I consume the resultant view as

content.innerHTML = await page.render();

from my main module.

The only way I am able to do this is by having my function call return yet another template containng the actual JS code.

let myFunction = () => {
    return `
        alert('Yo');
        document.getElementById('myBtn').textContent = 'Duh'
        `
}

however, this creates a very ugly page where my entire JS code is added inline into the HTML and that I can no longer use double quotes in my js code.

Upvotes: 9

Views: 13302

Answers (3)

Rishav Sharan
Rishav Sharan

Reputation: 2932

Figured out my problem with the help of another forum.

"Scripts inserted into innerHTML don't run. You should try splitting the render function into render and onMount - the second one called just after the innerHTML line."

Architecting my app into;

let About = {
    render : async () => {
        let view =  /*html*/
            `
            <h1> About </h1>
            <button id="myBtn" type="button" >Try it</button> 
            `
        return view
    },
    after_render: async () => {
        document.getElementById("myBtn").addEventListener ("click",  () => {
            console.log('Yo')
            alert('Yo')
        })
    }

}

export default About;

and consuming it as;

content.innerHTML = await page.render();
await page.after_render();

solved my problems.

Upvotes: 5

Jeremi G
Jeremi G

Reputation: 421

You can give the onClick a reference to your function, by not providing the () when referencing it. This will tell JavaScript to call the function and attempt to pass it the event's arguments when it gets triggered.

onclick=`${myFunction}`

will get called everytime the element is clicked.

Upvotes: 2

Jordan Enev
Jordan Enev

Reputation: 18644

Here's how you can invoke a function in a template literal:

const func = () => 'Hello'

console.log(`${func()} World`)

Upvotes: 9

Related Questions