Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass javascript function as data-* attribute and execute

We know such syntaxes as below, when defining a value for onClick attribute:

<button type="submit" onclick="alert('hi');"></button>
<button type="submit" onclick="doWork"></button> <!-- This one doesn't work -->
<button type="submit" onclick="doWork()"></button>
<button type="submit" onclick="doWork('Mike', 2)"></button>

What I'm interested in is to define a custom data-attribute and execute the value as follows:

<button type="submit" data-callback="alert('hi');"      class="marker"></button>
<button type="submit" data-callback="doWork"            class="marker"></button>
<button type="submit" data-callback="doWork()"          class="marker"></button>
<button type="submit" data-callback="doWork('Mike', 2)" class="marker"></button>

<script type="text/javascript">
    jQuery("body").on("click","button.marker", function(e) {
        var callback = jQuery(e.currentTarget).data("callback");

        // Now I need to execute the callback no matter of the format
        // 1. Execute as function's body
        // 2. Or by function 'name'
        // 3. Or by function 'name' with 0 parameters
        // 4. Or by function 'name' with n parameters
    })

    function doWork(name, nr){
        var personName = name || "Unnamed";
        var personNr = nr || 0;
        alert("Name is: " + personName + " Nr: " + personNr);
    }
</script>

I've pasted the sample to jsBin

How to accomplish same behaviour using custom data-attributes?

like image 614
Cristian E. Avatar asked May 04 '15 10:05

Cristian E.


6 Answers

One way is to use eval()

jQuery(".container").on("click", "button.marker", function (e) {
    var callback = jQuery(e.currentTarget).data("callback");

    var x = eval(callback)
    if (typeof x == 'function') {
        x()
    }
});

Demo: Fiddle

Note: Make sure it is safe in your environment, ie there is no possibility of script injection because of bad input from users

  • Why is using the JavaScript eval function a bad idea?
  • When is JavaScript's eval() not evil?
  • eval() isn’t evil, just misunderstood
  • Eval is Evil, Part One
like image 85
Arun P Johny Avatar answered Oct 14 '22 01:10

Arun P Johny


I think a better idea would be to dynamically bind the events and trigger them. If you wanted them to only be known by other code, you could use custom events.

<button type="submit" class="marker marker1"></button>
<button type="submit" class="marker marker2"></button>
<button type="submit" class="marker marker3"></button>
<button type="submit" class="marker marker4"></button>

<script>
    var $markers = $('.marker');
    $markers.filter('.marker1').bind('customCallback', function(){ alert("hi"); });
    $markers.filter('.marker2').bind('customCallback', function(){ doWork(); });
</script>

Then your other components could invoke them with $(selector).trigger('customCallback');

like image 42
Taplar Avatar answered Oct 14 '22 02:10

Taplar


Simply with :

 $("body").on("click","button.marker", function(e) {
     eval($(this).data("callback"));
 })
like image 24
Jeremy Thille Avatar answered Oct 14 '22 01:10

Jeremy Thille


If you really wanted to pass functions (with or without parameters) from one thing to another without binding them as events you could do it this way (I started from @Taplar's answer)

<button type="submit" class="marker marker1"></button>
<button type="submit" class="marker marker2"></button>
<button type="submit" class="marker marker3"></button>
<button type="submit" class="marker marker4"></button>

<script>
  var $markers = $('.marker');
  $markers.filter('.marker1').get(0).customCallback =  doWork;
  $markers.filter('.marker2').get(0).customCallback = function(){ 
    doWork(arg0,arg1); 
  };
</script>

Then you could access them in your other component as:

<script>
  $('.marker').each(function(){
    var  thisFunction = $(this).get(0).customCallback;
    //do something useful with thisFunction
  });
</script>
like image 24
Michiel Cornille Avatar answered Oct 14 '22 00:10

Michiel Cornille


You can just bind a function as a data attribute

const ele = $('button');

ele.data('onClick', evt => {
    alert('bye');
})

ele.click(evt => {
    const ele = $(evt.target);
    ele.data('onClick')(evt);
})
like image 36
Mojimi Avatar answered Oct 14 '22 00:10

Mojimi


Another way is using window[func](args).

Similar to the eval(), but you will have to store the function name and the argument separately in the HTML attribute.

Here is a quick example... CodePen

<button type="submit" data-func="Angel" data-args='use me instead of evil()' class="marker">TEST</button>

<script type="text/javascript">

    //=== The Listener =====
    $(".marker").on("click",function(){

        // Get the function name and arguments
        let func = $(this).attr("data-func");
        let args = $(this).attr("data-args");

        // Call the function
        window[func](args);
    })


    //=== The Function =====
    function Angel(msg){
        alert(arguments.callee.name + " said : " + msg);
    }
</script>
like image 22
Asuka165 Avatar answered Oct 14 '22 02:10

Asuka165