Max Frai
Max Frai

Reputation: 64266

Filling array with numbers

I have such situation: There is 8 div-blocks with ids like 'rateN_wrapper' where is 'N' is the number of div:

<div id="rate1_wrapper">
  <a href="#" id="0_1">...</a>
  <a href="#" id="0_2">...</a>
  <a href="#" id="0_3">...</a>
</div>

<div id="rate2_wrapper">
  <a href="#" id="1_1">...</a>
  <a href="#" id="1_2">...</a>
  <a href="#" id="1_3">...</a>
</div>

...

var ratings = new Array();
for (i=0; i < 8; i++)
{
    ratings[i] = -1; // Default is unrated

}

for (i=0; i < 8; i++)
{
    $('#rate' + i + '_wrapper a').click(function() {
        ratings[i] = parseInt( $(this).attr('id').split('_')[1] );
        console.debug(ratings);
    });
}

My work is to fill array in need place with clicked link's id (parsed). But it's always changes only latest element of array (8). Why?

Upvotes: 3

Views: 1592

Answers (2)

A. Levy
A. Levy

Reputation: 30566

Because the function you create is closing over the i variable. It sees a reference to i at its current value instead of the value when you created the function. After the for loop exits, i will be 8, so all your anonymous functions will update ratings[8]. I think this might fix it:

for (i=0; i < 8; i++)
{
    var idx = i;
    $('#rate' + idx + '_wrapper a').click(function() {
        ratings[idx] = parseInt( $(this).attr('id').split('_')[1] );
        console.debug(ratings);
    });
}

I'm not sure if declaring the var inside the loop body will rebind it for every iteration. If so, then the anonymous function will only see the value that idx had at the time the function was created. Here is a way that I know will work:

function CreateHandler(idx) {
    return function() {
        ratings[idx] = parseInt( $(this).attr('id').split('_')[1] );
        console.debug(ratings);
    }
}

for (i=0; i < 8; i++) {
    $('#rate' + idx + '_wrapper a').click(CreateHandler(i));
}

So you create a function that will create an anonymous function with the correct index. The returned anonymous function will see the value of idx at the time of its creation.

Upvotes: 1

Jan Willem B
Jan Willem B

Reputation: 3806

That's a problem caused by the closure in the for loop. You could lookup the id by parsing the parent id:

for (i=0; i < 8; i++)
{ 
  $('#rate' + i + '_wrapper a').click(function() {
    var parentId = $(this).parent('div').attr('id');
    var index = /\d/.exec(parentId);
    ratings[index] = parseInt( $(this).attr('id').split('_')[1] );
  });
}

Upvotes: 2

Related Questions