Reputation: 64266
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
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
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