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?
问题:
回答1:
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.
回答2:
I suggest you use Select2 if it is not too late. It looks the same as Chosen but has a way better API and docs.
With select2, it would be something like [untested code]
var results = [];
$("#e11").on("change", function(e) {
results.push(e.val)
})
回答3:
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.
回答4:
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. :)
回答5:
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. :)
回答6:
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');
});