Event binding on dynamically created elements and passing parameters

為{幸葍}努か 提交于 2020-01-05 09:11:19

问题


I found similar questions while searching for a solution for my problem but I don't think its quite that what I'm looking for.

Using jQuery's .on() is no brainer for binding events on dynamically created elements, but I got stuck while trying to pass different parameters to call different functions. After reading https://developer.mozilla.org/en/JavaScript/Guide/Closures I came up with the following working example, but I would like to know if its the best way to do it or if there is a more elegant solution?

http://jsfiddle.net/V25Zc/

Plus I often read that using eval() isn't a best practice due to vulnerability issues but is there another way to build dynamic function names?

Edit:

Thanks a lot for everyone for the great answers! Did one of the answers got deleted though? I liked that one because of the hint to store the parameter in an attribute. Thanks again all!


回答1:


The point of event delegation is that you don't need to bind an event to every single element (or to the same element multiple times), just once to the common parent, like so:

function createLinks() {

    var $container = $("#container"),
        links = "";



    for (var i=0; i < 4; i++) {
        links += '<a class="linklink" href="#">Link_' + i + '</a>';
    }

    $container.html(links).on( "click", ".linklink", function(){
        console.log( "fn action"+$(this).index());
    });
}

createLinks();

To avoid using eval, you could have an array of functions and call them by index:

arrayOfFunctions[ $(this).index() ]();

http://jsfiddle.net/V25Zc/2/




回答2:


If each action function actually has to be a different function (rather than one function that acts different based on the index passed to it), then I'd do it this way by putting an attribute on the link and fetching it upon click which you can see it work here: http://jsfiddle.net/jfriend00/gFmvG/.

function action0(){ console.log("fn action0"); }
function action1(){ console.log("fn action1"); }
function action2(){ console.log("fn action2"); }
function action3(){ console.log("fn action3"); }

var actions = [action0, action1, action2, action3];

function createLinks() {

    var $container = $("#container"),
        links = "";

    for (var i=0; i < 4; i++) {
        links += '<a id="link_' + i + '" href="#" data-num="' + i + '">Link_' + i + '</a>';
        $container.on("click", '"#link_' + i + '"', function() {
            actions[$(this).data("num")]();
        });
    }

    $container.html(links);
}

createLinks();

If you don't have to have separate functions for each action, I'd do it like this which you can see here: http://jsfiddle.net/jfriend00/Z8Rq6/.

function doAction(index) {
    console.log("fn action" + index);
}

function createLinks() {

    var $container = $("#container"),
        links = "";

    for (var i=0; i < 4; i++) {
        links += '<a id="link_' + i + '" href="#" data-num="' + i + '">Link_' + i + '</a>';
        $container.on("click", '"#link_' + i + '"', function() {
            doAction($(this).data("num"));
        });
    }

    $container.html(links);
}

createLinks();

This could also be done with an executing closure which locks in the index value, but I find that syntax somewhat less readable (it takes too many brain cycles to read the code and know what it's doing) so I prefer this way with the attribute.




回答3:


Put your functions in an object

var myFuncs = {
action0:function(){ console.log("fn action0"); },
action1:function(){ console.log("fn action1"); },
action2:function(){ console.log("fn action2"); },
action3:function(){ console.log("fn action3"); }
};

var funcNumber = "3";

for (var i=0; i < 4; i++) 
{
    links += '<a id="link_' + i + '" href="#">Link_' + i + '</a>';
    (function(myI)
    {
         $container.on("click", '"#link_' + i + '"', function()
         {
              myfuncs["action"+funcNumber](mI);
         });
    })(i);
}

course if they are being made on the global scope you could also do

for (var i=0; i < 4; i++) 
{
    links += '<a id="link_' + i + '" href="#">Link_' + i + '</a>';
    (function(myI)
    {
         $container.on("click", '"#link_' + i + '"', function()
         {
              window["action"+funcNumber](mI);
         });
    })(i);
}



回答4:


It looks like your original problem was that you wanted to call a function whose name would be determined by the parameter passed in. Are these functions all global in scope? If so, I would just do this:

function helpCallback(index) {
    return function() {
        window['action' + index]();
    }
}

This has the added advantage that, if you ever wanted to pass arguments to actionX, you do so by passing these arguments after index with the following modification

function helpCallback(index) {
    var args = arguments;
    return function() {
        window['action' + index].apply(null, [].slice.call(args, 1));
    }
}

So helpCallback(1, "foo"); would return a function that calls action1('foo')




回答5:


I wouldn't personally bother with creating IDs and then referencing them. Why not use closures within bindings to actual elements you've created.

For example, you can do something like

function createLinks() {

    var $container = $("#container");

    for (var i=0; i < 4; i++) {
        var link = $('<a href="#link' + i + '">Link_' + i + '</a>');
        $container.append(link);
        (function(){
            var index = i;
            link.click(function(){
                alert("Do my thing " + index);
            });
        })();
    }

}

createLinks();


来源:https://stackoverflow.com/questions/8774335/event-binding-on-dynamically-created-elements-and-passing-parameters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!