user706420
user706420

Reputation: 1205

Select2 with Drag and Drop Sorting

Select2 (v3.5.1) have a Drag&Drop function but only für "input" fields. I need a value/text combination, so only a selectbox is for me the right choice.

I found a (part) solution for my problem here: http://joevanderjagt.com/better-multiple-select-with-sorting/

But, its have a bug. Its working fine with sorting tags, but not, if user only add tags without sorting. I have created a jsfiddle: http://jsfiddle.net/s8v3su36/

<select id="test" size="1" multiple="multiple" style="width:400px">
    <option value="a">AAA</option>
    <option value="b">BBB</option>
    <option value="c">CCC</option>    
</select>

(function($){
    $.fn.extend({
        select2_sortable: function(){
            var select = $(this);
            $(select).select2();
            var ul = $(select).prev('.select2-container').first('ul');
            ul.sortable({
                placeholder : 'ui-state-highlight',
                forcePlaceholderSize: true,
                items       : 'li:not(.select2-search-field)',
                tolerance   : 'pointer',
                stop: function() {
                    $($(ul).find('.select2-search-choice').get().reverse()).each(function() {
                        var id = $(this).data('select2Data').id;
                        var option = select.find('option[value="' + id + '"]')[0];
                        $(select).prepend(option);
                    });
                }
            });
        }
    });

    $('#test').select2_sortable();
}(jQuery));

Add first "CCC" and now "BBB" and press debug button. You will see order "AAA, BBB, CCC" but must be "CCC,BBB,AAA"

Now use drag&drop the move "BBB" as first entry. click again debug button and see correct order "BBB,CCC,AAA".

Can anybody help here? I wish that add a entry is sorting the option in select too. :)

POSSIBLE SOLUTION: http://jsfiddle.net/s8v3su36/4/

Upvotes: 1

Views: 9726

Answers (5)

Shubham Verma
Shubham Verma

Reputation: 178

I have simplified it; you can try using this code. I hope it works:

var selectable = $('#id').select2();

selectable.next().children().children().children().sortable({
    containment: 'parent', stop: function (event, ui) {
        ui.item.parent().children('[title]').each(function () {
            var title = $(this).attr('title');
            var original = $( 'option:contains(' + title + ')', selectable ).first();
            original.detach();
            selectable.append(original)
        });
        selectable.change();
    }
});

Upvotes: 0

Petr P&#225;nek
Petr P&#225;nek

Reputation: 389

I rewrote the code from (@ambroiseRabier). My code is more clean, don't use $(ul).find to find selected options. Instead it uses the passed ui element, to find selected options and original select element that needs to be updated. This version works properly if you have more Select2 instances in the web page.

(function ($) {
$.fn.select2Sortable = function () {
    this.next().children().children().children().sortable({
        containment: 'parent', stop: function (event, ui) {
            var originalSelectElement = ui.item.parent().parent().parent().parent().prev();
            ui.item.parent().children('[title]').each(function () {
                var title = $(this).attr('title');
                var originalOptionElem = $(originalSelectElement).children('[value="' + title + '"]');
                originalOptionElem.detach();
                $(originalSelectElement).append(originalOptionElem)
            });
            $(originalSelectElement).change();
        }
    });
};
})(jQuery);

Upvotes: 0

Alexander
Alexander

Reputation: 7832

With vue.js - please consider using this component (compact on the page, comfortable to use even with long list of options):

https://www.npmjs.com/package/vue-libs-multi-select-with-order enter image description here

Upvotes: 1

user706420
user706420

Reputation: 1205

Added:

$(select).on("change", function(e)
{
    if (e.added)
    {
        var select = $(this);
        var ul = $(select).prev('.select2-container').first('ul');
        $($(ul).find('.select2-search-choice').get().reverse()).each(function() {
            var id = $(this).data('select2Data').id;
            var option = select.find('option[value="' + id + '"]')[0];
            $(select).prepend(option);
        });
    }
});

Upvotes: 0

phedoreanu
phedoreanu

Reputation: 2736

Your magic debug button just outputs the <select> children, which remain the same when the page first loads or you add options to the select2 div.

Only after you stop the drag, the stop function gets executed and rearranges the <option> tags.

Try to reorder your <select> on the add event too.

Upvotes: 0

Related Questions