BlairHippo
BlairHippo

Reputation: 9658

jQuery sortable code not behaving like I expect

I'm using jQuery to allow drag-n-drop between two lists, and I'm not getting the behavior I expect.

Each list comes in two pairs with the ids teams_in_set<set-number> and teams_not_in_set<set-number>, all members of the class connected-sortable. There will be an arbitrary number of these pairings on the page, with an set-number of 0 at the end, representing a new set being created (as opposed to an existing set being edited).

I'm setting it up with the following function in $(document).ready:


    var teams_in_set_pattern = /^teams_in_set(\d*)$/;
    $(function() {
        var connected_list = $(".connected-sortable");
        for (var i = 0; i < connected_list.length; i++) {
            var id = connected_list[i].id;
            if (teams_in_set_pattern.test(id)) {
                var set_num = id.match(teams_in_set_pattern)[1];
                var teams_in = "#teams_in_set" + set_num;
                var teams_out = "#teams_not_in_set" + set_num;

                if (set_num > 0) {
                    $(teams_in + ", " + teams_out).sortable({
                        revert: true,
                        connectWith: ".connected-sortable", 
                        cursor: 'move', 
                        receive: function(event, ui) {
                            update_teams(set_num);
                        } 
                    }).disableSelection();
                }
                else {
                    $(teams_in + ", " + teams_out).sortable({
                        revert: true,
                        connectWith: ".connected-sortable", 
                        cursor: 'move', 
                    }).disableSelection();
                }
            }
        }
    });

The idea is that when a team is moved from one list to the other, the update_teams(set_num); line gets called, triggering some Ajax that updates the database. The problem is the variable set_num; it seems like rather than retain the value it had when receive: was populated, it has the value it was last set to, which always winds up being 0.

What am I misunderstanding? And what do I need to do to get the behavior I want?

Upvotes: 0

Views: 85

Answers (1)

Steve Campbell
Steve Campbell

Reputation: 3605

This is a common issue in async Javascript. By the time the update_teams runs, the loop has run its course.

See similar question: JavaScript closure inside loops – simple practical example

I usually move the problem code into its own function, e.g.

function doIt(teams_in, teams_out, set_num) {
   if (set_num > 0) {
                $(teams_in + ", " + teams_out).sortable({
                    revert: true,
                    connectWith: ".connected-sortable", 
                    cursor: 'move', 
                    receive: function(event, ui) {
                        update_teams(set_num);
                    } 
                }).disableSelection();
            }
    else {
                $(teams_in + ", " + teams_out).sortable({
                    revert: true,
                    connectWith: ".connected-sortable", 
                    cursor: 'move', 
                }).disableSelection();
    }
}

Upvotes: 1

Related Questions