TimH - Codidact
TimH - Codidact

Reputation: 1457

Save and restore Sortable positions from two lists

I'm using RubaXa's excellent Sortable JS library to allow drag-and-drop rearranging of divs on a Bootstrap-based dashboard. Since the divs are all in 2 columns (left and right), I have the columns defined with ids of "leftColumn" and "rightColumn".

In order to allow dragging between columns, I set up both sortables with the same group, like this:

Sortable.create(leftColumn, {
    group: 'dash_sections',
});
Sortable.create(rightColumn, {
    group: 'dash_sections',
});

Now I am trying to load and save the order from both lists (the entire group). I placed data-id fields in each of the div tags, and I'm trying to use the following code to save and restore the order of everything.

Sortable.create(rightColumn, {
    group: 'dash_sections',
    store: {
        get: function (sortable) {
            var order = localStorage.getItem(sortable.options.group);
            return order ? order.split('|') : [];
        },

        set: function (sortable) {
            var order = sortable.toArray();
            localStorage.setItem(sortable.options.group, order.join('|'));
        }
    }
});

However, I'm only saving and restoring the order for that column, not the entire group. I eventually want to have the group's order stored in a single string in the database. How do I go about saving and restoring the entire group's order?

Update: I put similar code in both sortable.create functions, using "leftcol" and "rightcol" instead of sortable.options.group. This properly saves the order of each sortable as long as you don't drag between columns. I'm still looking for a way to save the order even when dragging between columns.

Upvotes: 2

Views: 3117

Answers (1)

Varinder
Varinder

Reputation: 2664

Here's how I implemented a similar functionality

Introduced a category flag to sortable options:

var leftColumnOptions = {
    group: "dash_sections",
    category: "left_column",
    store: setupStore()
};

var rightColumnOptions = {
    group: "dash_sections",
    category: "right_column",
    store: setupStore()
}

setupStore function checks for localStorage availability and applies get and set

function setupStore() {
    if (localStorageAvailable) { // basic localStorage check: (typeof (localStorage) !== "undefined")
        return {
            get: getValue,
            set: setValue
        };
    }
    return {}; 
}

getValue and setValue retreive and store item ids based on category name defined in options above

function getValue(sortable) {
    var order = localStorage.getItem(sortable.options.category);
    return order ? order.split('|') : [];       
}

function setValue(sortable) {
    var order = sortable.toArray();
    localStorage.setItem(sortable.options.category, order.join('|'));
}

It is a good idea to check for stored order information in localStorage before initializing Sortable, I'm using lodash for convenience

function applyState($section, categoryName) {
    if (localStorageAvailable) {
        var order = localStorage.getItem(categoryName);
        var itemIds = order ? order.split('|') : [];
        var $items = _.map(itemIds, function(itemId, index) {
            return $("[data-id='" + itemId + "'");
        });
        $section.append($items);
    }
}

usage would be:

applyState($(".js-left-column"), "left_column");
applyState($(".js-right-column"), "right_column");
// initialize sortable

Entire code:

HTML:

<div class="js-two-column-sortable js-left-column" data-category="left_column">
    <!-- elements -->
</div>
<div class="js-two-column-sortable js-right-column" data-category="right_column">
    <!-- elements -->
</div>

JS:

var localStorageAvailable = (typeof localStorage !== "undefined");

function getValue(sortable) {
    var order = localStorage.getItem(sortable.options.category);
    return order ? order.split('|') : [];       
}

function setValue(sortable) {
    var order = sortable.toArray();
    localStorage.setItem(sortable.options.category, order.join('|'));
}

function setupStore() {
    if (localStorageAvailable) {
        return {
            get: getValue,
            set: setValue
        };
    }
    return {}; 
}

function onAdd(evt) {
    setValue(this);
}

function applyState($section, categoryName) {
    if (localStorageAvailable) {
        var order = localStorage.getItem(categoryName);
        var itemIds = order ? order.split('|') : [];
        var $items = _.map(itemIds, function(itemId, index) {
            return $("[data-id='" + itemId + "'");
        });
        $section.append($items);
    }
}

var options = {
    group: "two-column-sortable",
    store: setupStore(),
    onAdd: onAdd
};

function init() {

    $(".js-two-column-sortable").each(function(index, section) {
        var $section = $(section);
        var category = $section.attr("data-category");
        var sortableOptions = _.extend({}, options, { category: category });
        applyState($section, category);
        $section.data("twoColumnSortable", new Sortable(section, sortableOptions));
    });
}

init();

Upvotes: 0

Related Questions