3

I'm trying to bind event handlers within a loop such as:

        var tabs = ['one', 'two', 'three', 'four']

        for(var i = 0; i < tabs.length; i++) {
            alert(tabs[i]);
            var id = i;
            $('#' + tabs[i]).bind('click', function() {
               loadTabs(id, tabs);
            });
        }

Which only keeps the last one bound (value 'four').

I'm trying to consolidate this code which currently does work:

        $('#one').click(function() {
            loadTabs(0, tabs);
        });

        $('#two').click(function() {
            loadTabs(1, tabs);
        });

        $('#three').click(function() {
            loadTabs(2, tabs);
        });

        $('#four').click(function() {
            loadTabs(3, tabs);
        });

Thought I might need a closure due to this post.

Community
  • 1
  • 1
bob_cobb
  • 2,229
  • 11
  • 49
  • 109

2 Answers2

5

You are right about what you read in the other post. You need to make a closure to bind the arguments to each single onclick handler:

$('#' + tabs[i]).bind(
    'click', 
    (function(id) {
        return function() 
        {
            loadTabs(id, tabs);
        };
    })(id)
);

You might also want to look into currying. In this example you might create a small helper function, which binds the first argument to a passed function and returns the new function.

function curry(func, arg1)
{
    return function()
    {
        func(arg);
    };
}

And then put it together like this:

$('#' + tabs[i]).bind(
    'click', 
    curry(function(id) { loadTabs(id); }, id)
);

Note that my curry function does not match the definition of currying, because it ignores any other argument. But it should work for your case.

Community
  • 1
  • 1
copy
  • 3,301
  • 2
  • 29
  • 36
1

As you are already using jQuery you can use jQuery.each for this task. Therefor you won't need to do it yourself with, as you correctly assumed, closures.

var tabs = ['one', 'two', 'three', 'four'];

$.each(tabs, function(idx, tab) {
    $("#" + tab).on("click", function() {
        alert(idx);
        //loadTabs(idx, tabs);
    })
});

jsfiddle

Andreas
  • 21,535
  • 7
  • 47
  • 56
  • So this right now is alerting the id name from the div in the html on the demo? – bob_cobb Dec 24 '11 at 11:15
  • Also, your method assumes you are going to be adding them in that particular order (of the tabs array). The point is to make this more modular so order doesn't matter. – bob_cobb Dec 24 '11 at 11:50
  • @bob_cobb: In my example the index of the current item in the array is alerted. But that is just for debugging; And your second comment makes no sense, because you are doing the same with your loop only much more complicated. Nonetheless, what do you mean by "more modular"? I can't think of any circumstance in what I would solve this particular problem you've posted in any other way. – Andreas Dec 24 '11 at 12:18