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

61 Views Asked by At

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?

1

There are 1 best solutions below

1
Nick Parsons On BEST ANSWER

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>