views:

43

answers:

2

I'm creating a jQuery plugin to do paging and encountered the following problem.

When I click on a page link created by the plugin below, it will always give we the value of the last index passed into the value i at the last iterator of the code below. If there are 4 pages, I will always get 4 if I press link 1, 2, 3 or 4. It seems that the reference to the delegate onclick also keeps a reference to the value of i instead of just the value.

Any Ideas? It's the options.onclick(i) that's acting strange.

$.fn.pager = function(options) {
    var defaults = {
        resultSet: undefined,
        onclick: function(page) { alert(page); return false; },
    };

    return this.each(function () {
        var rnd = Math.floor(Math.random()*9999)
        var result = '';
        for(var i = 1; i <= options.resultSet.PageCount; i++)
        {
            if(i == options.resultSet.PageCount)
                result += '<a href="#" id="' + rnd + '_pagerPage_' + i + '">' + i + '</a>';
            else
                result += '<a href="#" id="' + rnd + '_pagerPage_' + i + '">' + i + '</a>' + options.separator;
        }

        $(this).html(result);

        for(var i = 1; i <= options.resultSet.PageCount; i++)
        {
            $('#' + rnd + '_pagerPage_' + i).click(function() { options.onclick(i) });
        }
    });
}

I reduced the above code to just the problem case. So some checks re missing ;)

A: 

This is a classic problem: the value of i that gets used inside the option click event handler function is whatever value i has at the point at which the event fires (which will be 4, the final value it has in the loop), not the value it had at the point at which you assigned the event handler. The way round it is to create an extra function each time through the loop that has its own variable containing a copy of the value of i at the point it was called:

var createClickHandler = function(n) {
    return function() { options.onclick(n); };
};
$('#' + rnd + '_pagerPage_' + i).click( createClickHandler(i) );
Tim Down
Ok, that is indeed the problem, but the question is, how do we solve this?
Bjorn Bailleul
I've updated my answer.
Tim Down
I had hoped to avoid that, but thank you for your swift answer. It works like a charm and solves the reference problem.
Bjorn Bailleul
+1  A: 

It seems that the reference to the delegate onclick also keeps a reference to the value of i instead of just the value.

What you are experiencing is your first (unexpected) encounter with closures. It's not even a reference that is being passed, it's weirder than that. To understand what's going on (and it's critical that you do if you program in javascript, this is considered basic stuff these days) read my answers to the following related questions:

http://stackoverflow.com/questions/3572480/please-explain-the-use-of-javascript-closures-in-loops/3572616#3572616

http://stackoverflow.com/questions/61088/hidden-features-of-javascript/2047391#2047391

slebetman