Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you set a javascript function name as an html attribute?

Is it possible to write an html attribute that will store the name of a javascript function and then extract that val() and execute that function? Example:

<button id="example" data-function-name="showAllElements()">

and then in js/jq

fn = $('#example').data('function-name');

fn;
like image 387
Jarryd Goodman Avatar asked Dec 12 '14 16:12

Jarryd Goodman


People also ask

Can you call a JS function in HTML?

The first method is to call the JavaScript function in HTML. For this, you have to create a function then define this function either in the head section or body section of the HTML document. You can either create a link or a button and then an onclick() event is associated with them in order to call this function.

How do you call a function attribute in HTML?

To invoke this function in the html document, we have to create a simple button and using the onclick event attribute (which is an event handler) along with it, we can call the function by clicking on the button.

How do you name a JavaScript function?

A JavaScript function is defined with the function keyword, followed by a name, followed by parentheses (). Function names can contain letters, digits, underscores, and dollar signs (same rules as variables). The parentheses may include parameter names separated by commas: (parameter1, parameter2, ...)


2 Answers

Sure... assuming that showAllElements is global...

function showAllElements() {
  console.log("test!");
}
document.querySelector("button").addEventListener("click", function(e) {
  var functionName = this.getAttribute("data-function-name");
  window[functionName]();
});
<button id="example" data-function-name="showAllElements">x</button>

Now, let's say your attribute is actually something harrier, like: foo.bar.showAllElements...

var foo = {
  bar: {
    showAllElements: function() {
      console.log("test!");
    }
  }
};

document.querySelector("button").addEventListener("click", function(e){
    var functionName = this.getAttribute("data-function-name");
    // Split by "." and resolve each segment starting at the window. Invoke with ()
    functionName.split(".").reduce((o,n) => o[n], window)();
});
<button id="example" data-function-name="foo.bar.showAllElements">x</button>
like image 110
canon Avatar answered Oct 20 '22 17:10

canon


You can, yes. Whether you should is another question entirely, to which the answer is almost certainly "no" (in terms of executing the string; in terms of the alternative shown below, there are times it's useful).

The way you'd evaluate that snippet of code (what you have isn't just a function name, because of the ()) would be to use the dreaded eval:

eval(fn);

There's almost always a better option than using eval. (See below.)

eval example:

$("#example").on("click", function() {
  var fn = $("#example").attr("data-function-name");
  eval(fn);
});

function showAllElements() {
  alert("showAllElements was called");
}
<button type="button" id="example" data-function-name="showAllElements()">Click Me</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

One of the better options is to store your function references as properties on an object, and then use brackets notation to get the function reference based on the function name:

Example:

var functions = {
  showAllElements: function() {
    alert("showAllElements was called");
  }
};

$("#example").on("click", function() {
  var fn = $("#example").attr("data-function-name");
  functions[fn]();
});
<button type="button" id="example" data-function-name="showAllElements">Click Me</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Note that there, I'm just storing the function name, not arbitrary code.

Update: See canon's answer for a clever way to handle it if you have your functions nested inside an object, e.g. mumble.foo.doSomething, using reduce. (reduce is an ES5 feature, but it's polyfillable.)


Side note: Unless you're doing something more than just retrieving the value of a data-* attribute, don't use data, use attr. data initializes a data cache for the element, reads in all of the data-* attributes for that element, and copies them to cache. If you're not using it, there's no reason to do that. The idea that you use data to access data-* attributes is a common misconception.

like image 37
T.J. Crowder Avatar answered Oct 20 '22 16:10

T.J. Crowder