Search code examples
javascriptjqueryajaxrubaxa-sortable

Cannot reinitalize Sortable after ajax content update


I'm using Sortable to organise lists inside of parent groupings, which themselves are also sortable, similar to the multi example on their demo page, but with text. This works fine and uses code along the lines of:

var globObj = {};

function prepSortCats() {

    globObj.subCatsGroup = [];

    // Changing parent group order

    globObj.sortyMainCats = Sortable.create(catscontainer, {
        // options here omitted from example
        onUpdate: function( /**Event*/ evt) {
            // Send order to database. Works fine.
        }
    });

    // Changing sub list order

    globObj.subCatsGroup.forEach.call(document.getElementById('catscontainer').getElementsByClassName('subcatlist'), function(el) {
        var sortySubCats = Sortable.create(el, {
            // options here from example
            onUpdate: function( /**Event*/ evt) {
                // Send order to database. Works fine.
            }
        });
    });

}

Which is called when the page loads using:

$(document).ready(function () {
    // Sortable
    prepSortCats();
});

All good so far. However, the user can introduce new elements into any of the lists (sub or parent). In brief, any new elements added by the user are first added to the database, then the relevant section of the page is refreshed using ajax to pull the updated content from the database and display that. The user sees their newly added items added to one of the existing lists. Ajax call is as follows:

function refreshCategories() {
    var loadUrl = "page that pulls lists from database and formats it";
    $("#catscontainer")
        .html(ajax_load)
        .load(loadUrl);
    return false;
};

This works fine too. Except, Sortable no longer works. I can't drag any lists. My first thought was to destroy the existing Sortable instances and reinitialize them. Right after I called refreshCategories() I call the following:

if(globObj.sortyMainCats.length !== 0) {
    globObj.sortyMainCats.destroy();
}

if(globObj.subCatsGroup.length !== 0) {
    var i;
    for (i = globObj.subCatsGroup.length - 1; i >= 0; i -= 1) {
        globObj.subCatsGroup[i].destroy();
        globObj.subCatsGroup.splice(i, 1);
    }
}

prepSortCats();

But Sortable still has no effect. I introduced the global object (although controversial) so that I could target the Sortable instances outside their scope but I appear to have overlooked something. Any ideas? Apologies for not providing a working example. As I make various ajax calls to a server, I don't think this is possible here.

Update

I'm clearly misunderstanding some action that's taking place. Well, I should preface that by saying I missed that I could still organise the group/parent lists after reloading a section of the page by ajax with refreshCategories(). This is very much a secondary action to being able to sort the sub lists, which is what I noticed was broken and remains so.

But it did point out that although the entirety of $("#catscontainer") was being replaced with a refreshed version of the lists (and that's all it contains, list elements), Sortable still had some sort of instance running on it. I was under the understanding that it was somehow tied to the elements that were removed. Now I'm a bit more lost on how to get Sortable to either: (a) just start from scratch on the page, performing prepSortCats() as if it was a fresh page load and removing any previous Sortable instance, or (b) getting the remaining Sortable instance, after the ajax call to recognise the added elements.

Update 2

Making some progress.

Through trial and error I've found that right after calling refreshCategories(), calling globObj.sortyMainCats.destroy() is preventing even the group lists from being ordered. Then if I call prepSortCats() after this, I can move them again. But not the sub lists.

This isn't conclusive but it looks like I'm successfully destroying and reinitializing Sortable, which was my goal, but something about the ajax loaded elements isn't working with Sortable.


Solution

  • I was looking for the answer in the wrong place, being sure it was an issue with ajax loaded content and the dom having some inconsistencies with what Sortable expected.

    Turns out it was an asynchronous problem. Or, to put it simpler, the section of the page being loaded by ajax wasn't quite ready when Sortable was being asked to be reinitalized.

    For anyone having the same trouble, I changed:

    $("#catscontainer")
        .html(ajax_load)
        .load(loadUrl);
    

    to

    $("#catscontainer")
        .html(ajax_load)
        .load(loadUrl, function() {
             reinitSortable();
        });
    

    where reinitSortable() is just a function that fires off the destroy and prepSortCats() functions similar to how they're displayed above.