I am using Chosen's Multiple selection. I want to be able to track user selected order. For example, if a user select option2 first then option1, I want to get the result in the order of option2 and option1. But chosen sorts user selected options. Is there a way I can tell chosen to not sorting the result?
-
Are you referring to [this](http://harvesthq.github.com/chosen/)? – lonesomeday Sep 12 '12 at 20:08
-
jQuery Chosen does not keep track of the selected order, and hacking it in requires rewriting a lot of code. – Blaise Nov 27 '13 at 14:49
7 Answers
I wrote a simple plugin to use along with Chosen. It allows you to retrieve the selection order of a Chosen multiple select element, and also to set it from an array of ordered values.
It is available on Github : https://github.com/tristanjahier/chosen-order
It is compatible with Chosen 1.0+ and with both jQuery and Prototype versions. There is also a plugin for each framework, which let you do things like this:
Retrieve the selection order
var selection = $('#my-list').getSelectionOrder();
Set the selected values in order
var order = ['nioup', 'plop', 'fianle']; // Ordered options values
$('#my-list').setSelectionOrder(order);
Check it out.

- 1,127
- 1
- 12
- 27
There is a https://github.com/mrhenry/jquery-chosen-sortable/ plugin now available, which does the job for chosen v1.
For newer versions of chosen, you need to replace chzn- with chosen- in the github JS file.
To use, it I use the following code:
jQuery('#myselect').addClass('chosen-sortable').chosenSortable();
It works very well, but you will need some more code, when editing the field again to re-order the elements after chosen has loaded.
I use the following for this. Given a list of sortedElements and $select = jQuery('#myselect'):
var $container = $select.siblings('.chosen-container')
var $list = $container.find('.chosen-choices');
// Reverse the list, as we want to prepend our elements.
var sortedElements = sortedElements.reverse();
for (var i = 0; i < sortedElements.length; i++) {
var value = sortedElements[i];
// Find the index of the element.
var index = $select.find('option[value="' + value + '"]').index();
// Sort the item first.
$list
.find('a.search-choice-close[data-option-array-index="' + index + '"]')
.parent()
.remove()
.prependTo($list);
}
This works very well here.

- 279
- 2
- 5
-
2FWIW I had to use `.parent().detach().prependTo($list)` since the combination of `remove` and `prependTo` doesn't copy over the event handler on the `search-choice-close` link. We're using an older version of Chosen, though, from the `chzn-xxx` days. – Dave Newton Feb 18 '14 at 15:40
-
1This also won't work if you are using optgroups as indexes will be off. To fix it, you can modify the code: `var elem = $select.find('option[value="' + value + '"]'); var index = elem[0].index; index = index + elem.parent().index()+1;` – Artūrs Sosins May 06 '14 at 15:05
I injected a custom .change()
event handler to make it work:
$('.chosen-select').chosen({});
to:
$('.chosen-select').chosen({}).change((event, info) => {
if (info.selected) {
var allSelected = this.querySelectorAll('option[selected]');
var lastSelected = allSelected[allSelected.length - 1];
var selected = this.querySelector(`option[value="${info.selected}"]`);
selected.setAttribute('selected', '');
lastSelected.insertAdjacentElement('afterEnd', selected);
} else { // info.deselected
var removed = this.querySelector(`option[value="${info.deselected}"]`);
removed.setAttribute('selected', false); // this step is required for Edge
removed.removeAttribute('selected');
}
$(this).trigger("chosen:updated");
});
Note this moves the DOM in case of selection and no movement in case of deselection. The setAttribute
/removeAttribute
is to bring about visible change in <option>
DOM.
Hope this help someone still looking for a way to do it without doing anything extra on submit.
PS: compact jQuery version of this code can be written if needed. :)

- 32,612
- 11
- 57
- 93
You can add/remove items yourself on change event.
// Your collection Array
var collectionArray = []
// make change event on chosen select field
chosenSelect.change(function () {
// first get the chosen results which might be in wrong order
var currentValues = $(this).val();
// get your current collection that is in the right order
var pastValues = collectionArray;
// see if you need to add or drop
if (currentValues.length > pastValue.length) {
// loop to get just the new item
pastValues.forEach(function(pastValue) {
currentValue = $.grep(currentValue, function(newItemOnly) {
return newItemOnly != pastValue;
});
});
// add your newItemOnly
collectionArray.push(currentValue[0]);
} else {
// here loop to get only the dropped value
currentValues.forEach(function(currentValue) {
pastValues = $.grep(pastValues, function(droppedValueOnly) {
return droppedValueOnly != currentValue;
});
});
// drop the value dropped from your collection
collectionArray = $.grep(collectionArray, function(updatedArray) {
return updatedArray != pastValues[0];
});
}
});

- 131
- 1
- 3
-
Agree! This is the best answer, but there are some issues with variable names used in this example + it is way better to use it with element dataset rather than that global variable, that way you can have more elements with the same class or name and control their output easily, thanks – Dejan Dozet Aug 03 '19 at 09:33
Hope this is useful for folks who use older version of select2 (less than v4). select2-selecting and select2-removing options are helpful in this case. Using an array and appending the values once we select, we can maintain the order of selection and while de-selecting a particular option, we can find the index and remove it from the array using splice().
var selected = [];
$('#multiSelect').on("select2-selecting", function(evt) {
var selectedOption = evt.val;
selected.push(selectedOption);
}).on("select2-removing", function(evt) {
index = selected.indexOf(evt.val);
selected.splice(index,1);
});
For version 4 and above, select2:select and select2:unselect can be used. :)

- 31
- 5
This will arrange in order of your selection
$("select").on('select2:select', function (e) {
var elm = e.params.data.element;
$elm = jQuery(elm);
$t = jQuery(this);
$t.append($elm);
$t.trigger('change.select2');
});

- 3,336
- 3
- 27
- 37

- 127
- 2
- 6