Search code examples
javascriptonclickanonymous-function

Attach an anonymous function to an "onclick" attribute of a link


On various pages of a website I generate via JavaScript different click handlers attached to links in the innerHTML of an specific page element. I do it with a uitilty function like this:

function addClickLink(detail, detailHandler) {
    element.innerHTML = `Info about <a href="#" onclick="${detailHandler.name}(); return false;">${detail}</a>`
}

Calling addClickLinkworks works when detailHandler is a defined function like

function heliumHandler () { ... }


addClickLinkworks("Helium", heliumHandler)

but not when I call addClickLinkworks with an anonymous function:

addClickLinkworks("Helium", function() { ... })

How can I write the "onclick" string for anonymous functions?


Solution

  • You could wrap the stringified version of the function, and then call it using (<stringified function source)() so that the onclick treats it as a function expression (rather than a statement):

    const element = document.getElementById("element");
    function addClickLink(detail, detailHandler) {
      element.innerHTML = `Info about <a href="#" onclick="(${detailHandler})(); return false;">${detail}</a>`;
    }
    
    // This works:
    //function heliumHandler() { console.log('function declaration); }
    //addClickLink("Helium", heliumHandler)
    
    // And so does this:
    addClickLink("Helium", function() { console.log('function expression'); })
    <div id="element"></div>

    However, I wouldn't suggest this, as it can fail for native functions for example, and won't work correctly for bound functions. Rather than doing that, I would recommend that you create a HTML element and add your listener to that using .addEventListener():

    const element = document.getElementById("element");
    function addClickLink(detail, detailHandler) {
      const fragment = document.createDocumentFragment();
      const textNode = document.createTextNode("Info about ");
      
      const anchor = document.createElement('a');
      anchor.href = "#";
      anchor.innerText = detail;
      anchor.addEventListener("click", e => {
        e.preventDefault(); // similar to return false in your previous `onclick`
        detailHandler();
      });
      
      fragment.appendChild(textNode);
      fragment.appendChild(anchor);
      element.replaceChildren(fragment);
    }
    
    // This works:
    // function heliumHandler() { console.log('function declaration); }
    // addClickLink("Helium", heliumHandler)
    
    // And so does this:
    addClickLink("Helium", function() { console.log('function expression'); })
    <div id="element"></div>