Andrew Klatzke
Andrew Klatzke

Reputation: 544

Passing an array of functions as a parameter

Here's my code:

function test(e, f) {
    for (var i = 0; i < e.length; i++) {
        $('#clickme').append("<button id='op" + i + "'>" + e[i] + "</button>")
        $('#op' + i).click(function () {
            f[i]();
        })
    }
}


$(function postPunk() {
    var func1 = function () {
        alert('1');
    }
    var func2 = function () {
        alert('2');
    }
    var func3 = function () {
        alert('3');
    }
    test(['Option1', 'Option2', 'Option3'], [func1, func2, func3]);
})

The click events aren't calling the functions. If I place an alert test in the click event, it fires fine.

Any ideas why this isn't working? It seems to be a problem with passing the array of functions as a parameter. Is there a better way to do this?

Upvotes: 3

Views: 285

Answers (4)

N. Taylor Mullen
N. Taylor Mullen

Reputation: 18301

Here's how I got it to work: http://jsfiddle.net/fH2Dk/3/

function test(e, f){    
     for(var i = 0; i < e.length; i++) {
         (function(i) {
            $('#clickme').append("<button id='op" + i + "'>" + e[i] + "</button>");
            $('#op' + i).click(function(){
                f[i]();
            });
        })(i);    
    }
}

Upvotes: 0

Guffa
Guffa

Reputation: 700182

The code in the callback function uses the value of i after the loop has ended, so it points to an index outside the array. You need a closure in the loop so that each iteration gets its own instance of the variable:

function test(e, f) {
  for (var i = 0; i < e.length; i++) {
    $('#clickme').append("<button id='op" + i + "'>" + e[i] + "</button>");
    (function(i){
      $('#op' + i).click(function () {
        f[i]();
      });
    })(i);
  }
}

Upvotes: 1

gen_Eric
gen_Eric

Reputation: 227200

This seems to be the classic JavaScript issue, where they all be the last value (or undefined since f[3] doesn't exist), since that's the value of i after the loop.

Try to pass the function reference directly to the click handler.

function test(e, f) {
    for (var i = 0; i < e.length; i++) {
        $('#clickme').append("<button id='op" + i + "'>" + e[i] + "</button>")
        $('#op' + i).click(f[i])
    }
}

Or, another solution is to make a function that returns a function. This will allow it to "close" around i.

function test(e, f) {
    var makeFunc = function(i) {
        return function() {
            f[i]();
        }
    };
    for (var i = 0; i < e.length; i++) {
        $('#clickme').append("<button id='op" + i + "'>" + e[i] + "</button>")
        $('#op' + i).click(makeFunc(i))
    }
}

Upvotes: 4

Niet the Dark Absol
Niet the Dark Absol

Reputation: 324610

As with every other question of this type, i keeps on changing.

Instead, try this:

for( var i=0; i<e.length; i++) {
    (function(i) {
        // your code that depends on i not changing
    })(i);
}

Upvotes: 8

Related Questions