When initializing select2, options can be provided by using the data parameter in the constructor.
element.select2({
multiple: true,
placeholder: "Select some options",
data: ['p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
});
Thereafter, selections (not options) can dynamically be altered by using the data api; for example
element.select2('data', ['x', 'y', 'z']).
Is there any way to dynamically change options?
I thought there was a ticket for this, but I can't seem to find it.
If there is time with Select2 4.0, this is on the list of things that we want to implement.
Is it now possible to change options (add, remove) dynamically? What is the API for that?
It is not currently possible to do this dynamically. We may look into this in the future, but for now it does not look like it will be making it into 4.0.
The general idea of what would need to happen is...
Which probably isn't that difficult, but I currently do not have the time to investigate the drawbacks or alternatives.
I have a working workaround (dirty add-hoc solution, but it works).
var $select = $('#id_of_native_select');
// save current config. options
var options = $select.data('select2').options.options;
// delete all items of the native select element
$select.html('');
// build new items
var items = [];
for (var i = 0; i < ...; i++) {
// logik to create new items
...
items.push({
"id": ...,
"text": ...
});
$select.append("<option value=\"" + ... + "\">" + ... + "</option>");
}
// add new items
options.data = items;
$select.select2(options);
+1 for a placeholder API
+1 for native API to add/remove/modify items dynamically. Workaround i'm using below -
function initSelect(){
$("#select").select2({
... options ...
});
}
....
$("#select").select2("destroy");
// possible loop
$("#select").append("<option value='1'>Text</option>");
initSelect();
The nature of dynamically changing content typically requires other methods anyways. I believe Select2 doesn't require a dynamic data method. Rather, a standard (example) added to the documentation of a basic dynamic data change would be a clear enough solution.
Iterating @razakj function-
var data = {
dataCat1 : [...],
dataCat2 : [...],
}
function changeData(dataCategory){
$(".selectDynamic").select2({
data: dataCategory,
...
});
}
$(".selectStatic").on( "change", function(){
$(".selectDynamic").select2("destroy");
$(".selectDynamic").html("<option><option>");
changeData( data[ $(this).val() ] );
});
changeData(data["dataCat1"]);
+1 for this feature request.
Obvious use-case is multiple tagging interfaces on the page, and a user adds a tag to one, it should appear as an option in the others. Destroying & re-creating the select2 instances causes a flash of unstyled content which is not optimal.
We already have something like this, imagine if select2 had this capability:
window.initSelect2Fields = function () {
$('[data-simple-select2]').select2();
$('[data-select2-taggings]').select2({
tags: true,
matcher: function (params, data) {
/* ... custom matcher ... */
}
}).on("select2:select", function(e){
$('[data-select2-taggings]').select2("addOption", e.params.data);
});
/* more custom select2 init code */
}
To implement the suggested workaround (complete with FOSC), I'd have to break out the initialization of tagging interfaces to an inner init function, something like this:
window.initSelect2Fields = function () {
$('[data-simple-select2]').select2();
var initSelect2Taggings = function() {
$('[data-select2-taggings]').select2({
tags: true,
matcher: function (params, data) {
/* ... custom matcher ... */
}
});
}
initSelect2Taggings();
$('[data-simple-select2]').on("select2:select", function(e){
$('[data-simple-select2]').append("<option id='"+e.params.data.id+"'>"+e.params.data.text+"</option");
$('[data-simple-select2]').select2("destroy");
initSelect2Taggings();
});
/* ... more custom select2 init code ... */
}
Personally, I'm not sure it's worth the additional maintenance weight.
+1 for this feature. It's common to alter the content of a dropdown dynamically and with the previous verion I had no problem.
+1 for this feature as well.
+1
Isn't it possible to make a workaround "query" function? If so, any drawbacks ?
I look at the docs but even thought i failed to make it work with the current version of select2, if anybody has an example would be ace.
+1
I've open an issue on StackOverflow, I don't know if it's related. My workaround is ugly, and I would love to fix it.
Just use change().
$('#myselect').html('<option>Whatever</option>').change()
Thanks @renandecarlo
$('#txtClassTeacher').html("<option value='"+res.source.id+"'></option>");
$('#select2-txtClassTeacher-container').text(res.source.truename);
+1
+1 Need a clean way to destroy and recreate. Using $.select2('destroy') then creating on the same element causes bugs to appear in the API. Bad news....
+1 The inability to dynamically change/disable options is definitely a major deal.
This seems to work for me...
$control.select2('destroy').empty().select2({data: [{id: 1, text: 'new text'}]});
+1 for this feature
Its pretty legendary how hard it is to do a simple update of the data when the user clicks the control input. In fact, I'm still not sure its possible.
I wrote this function that updates one select2-enhanced <select> based on the selection in another.
Example: In the "source" select you can select cities, in the "target" select, you can select streets. The streets available per city are provided in an object, and there can also be a default street for each city. If the user selects a different city and goes back to city A, the street he had selected last time for A is also remembered.
/**
* synchronize/filter options in one select with/by selection in another
* @param sourceId DOM id of source <select>
* @param targetId DOM id of target <select>
* @param options Available options indexed by source indices, e.g.:
* 1 -> 1 -> foo
* 2 -> bar
* 3 -> 5 -> baz
* @param defaults Any known default selections per source index, e.g.:
* 1 -> 2
*/
function syncSelectables(sourceId, targetId, options, defaults)
{
var source = $('#' + sourceId);
var target = $('#' + targetId);
var updater = function () {
var filter = source.val();
/* build options array */
var items = [];
$.each(options[filter], function (id, text) {
items.push({"id": id, "text": text});
});
/* recreate whole widget.
see https://github.com/select2/select2/issues/2830
*/
target.select2('destroy').empty().select2({data: items});
/* accommodate for selection possible or not */
target.prop('disabled', items.length < 2);
/* set default selection */
if (defaults[filter]) {
target.val(defaults[filter]).trigger('change');
}
};
// ensure consistency initially
updater();
// bind to any changes
source.change(updater);
// remember selections
target.change(function () {
defaults[source.val()] = target.val();
});
}
It might be useful for anybody who came here because he wanted to implement such a thing.
+1 I want this feature badly also.
Here is my data updater:
function refreshSelect($input, data) {
$input.html($('<option />')); # if a default blank is needed
for (var key in data) {
var $option = $('<option />')
.prop('value', data[key]['id'])
.text(data[key]['text'])
;
$input.append($option)
}
$input.trigger('change');
}
Here is how to use it:
<select id="my_select_input"></select>
var $input = $('#my_select_input');
var data = [
{
id: 42,
text: 'XX'
},
{
id: 43,
text: 'YY'
}
];
refreshSelect($input, data)
It works with and without select2
From 2 years, this is not implemented... I can't understand, this feature is obvious. We don't want to reinitialize the Select2, we don't want to destroy it and recreate, this is stupid, we want to set data, programmatically.
A proper way to do it with no native method:
var data = [{id: 1, text: "First value"}, {id: 2, text: "Second value"}];
var select = $("yourSelect");
$(data).each(function(k, o) {
select.append($("<option></option>").attr("value", o.id).html(o.text));
});
select.val([1, 2]);// An array of ids to select in data, remove if you dont need it
select.change();
This is especially a problem for ajax because you don't know in advance what the data will be
+1 @Cartman34
I totally agree. Your solution is the Dryer I found. Thank you very much for your tips.
What is the difference/advantage against my workaround by the way ?
Same could be said for my solution as well which uses the existing select2 api without any big hacks. Seems like there are enough solutions here already; I'm not sure why people are still having issues with this one.
Your solution destroys the select2 which would like to be avoided (ie: it requires to merge the original config).
People are still having issues since there is no easy way to update the data, like:
$input.val(data).select2('refresh');
// something like that, or even simpler
$input.val(data);
My solution (part of the code in a plugin)
var cmdbSelect2 = function(ele, single){
var option = {
language: 'zh-CN',
width: 'resolve',
}
if(single == true){
$.extend(option,{ multiple: true, maximumSelectionLength: 1 })
}
ele.data('cmdbSelect', option)
return ele.select2(option)
}
var selectReOption= function(ele, option){
var options = ele.data('cmdbSelect')
ele.data('cmdbSelect', $.extend({}, options, option))
ele.select2('destroy').select2(ele.data('cmdbSelect'))
}
My solution using .get or .post
$('#direccion_integracion').on('change', function (e) {
var id_direccion = $(this).find("option:selected").val();
$.get("catastro/catastro_direccion_integracion.php?id_direccion="+id_direccion,
function( data ) {
$(".direccion_integrar").select2("destroy");
$(".direccion_integrar").html( data );
$(".direccion_integrar").select2({});
});
});
so building off of @ova2 's post, I created a jQuery plugin that is supposed to accomplish the same thing
// Function to dynamically set a new set of options to a select2 element
(function($) {
$.fn.setNewSelect2Data = function(newData) {
var origOptions = this.data('select2').options.options;
this.empty().select2($.extend(origOptions, { data: newData }));
return this;
};
})(jQuery);
however it appears that this.data('select2').options.options no longer contains the current options that are set on initial initialization. Anyone know the proper way to get the current select2 options at runtime? (Yes, I've tried googling, however any search for "options" has results for select options, not the select2 initialization options.
With the last 4.0.3 version of select2, we see a weird behavior in this jsfiddle
At first click, you see that options are reset, minimumInputLength is gone when select2 is called again and at the next step, you see that data are appended to previous ones but other options are resetted.
In this case, we would the opposite, all data are replaced and previous options are kept. But in all cases, the data also set the DOM OPTION elements in the SELECT tag.
I could advise you to use your own function defining the select2 for this element with a data array in argument to always get the same options and only change the data.
You could also see my previous answer.
+1
@Cartman34 Your solution doesn't work for data sets that use a structure outside of the fixed { id: 0, text: 'value' } format.
However I'm in agreement that I may have to modify it to make a complete wrapper for select2 initialization as well, instead of just getting current options, unless someone else knows how to make select2 get it's initialization options at runtime.
Regards the API for doing dynamic loading: perhaps mimic the DataTables approach and make the ajax option more generic. Current practice seems to take an object that defines a mandatory url:
$('select').select2({
ajax: { url: '/path/to/search/endpoint' }
});
As I see it, this requires the dynamic data to come from a back-end source. This approach makes a strong coupling between the View and the Model, which in my opinion is not a good practice.
If the ajax option could also be a function, then the dynamic data could come from anywhere:
$('select').select2({
ajax: function(callbackFn) {
var newData = getMeSomeNewData();//can be from anywhere: local data or external ajax call.
callbackFn(newData); //has same effect as the old ajax response
}
});
A suggestion, for what it's worth. We use DataTables and Select2 a lot, and a consistent approach would be nice. :)
Which is the status of this?
+100
+1
+1
+1 But can anyone tell me if there is something wrong with @renandecarlo 's solution? Seems to work quite well.
+1 But can anyone tell me if there is something wrong with @renandecarlo 's solution? Seems to work quite well.
@mktcode There's nothing wrong with it as long as you're using only html <option> tags. It's when you're using data objects that don't have a fixed { id: '', text: ''} that the problem presents itself.
@Zxurian that doesn't seem so difficult. An extension of @renandecarlo's solution:
var $select = $('select#some_id');
var newDataObjects = [...whatever...];
var optns = newDataObjects.map(function(item) {
return '<option value="' + item.someVal + '">' + item.someName + '</option>';
});
$select.html( optns.join("") ).change();
@trevithj that's still staying with the traditional <option> tags. I forgot to post an addendum which probably would have helped, but with objects, you have the ability to use tempalteSelection, templateResult options, which don't use <option> tags at all, thus calling change() method on the original select doesn't work unless you do some extra data manipulation and transposition, which is just adding extra work, especially when you start dealing with ajax calls.
By having a method on the select2 adapter itself, you can just supply an array of objects of the same schema as the existing objects to it, and it'll use select2's own existing methods (templateSelection, templateResult) without having to write extra code around it, so your total code for updating options is just a single line like the initial poster requested.
newItemList = [
{ itemNum: 23, itemName: 'Shoe', itemShelf: 4, itemBin: 'C' },
{ itemNum: 52, itemName: 'Boot', itemShelf: 9, itemBin: 'A' },
{ itemNum: 88, itemName: 'Laces', itemShelf 2, itemBin: 'E' }
];
// or however you build / get your updated list
// actual code to update select2 options, nothing else needed
mySelect2Object.select2('data', newItemList);
This is a major hurdle for me. When implementing shift-click to select all elements, it takes two clicks to refresh and I cannot seem to figure out how to make it trigger instantly for the life of me!!
```// Logic for selecting all
jQuery(view_field).on("select2:selecting", function(e) {
// what you would like to happen
//console.log('select2 select', event.shiftKey);
if(shifted) {
// select all
$select2 = jQuery(view_field);
$select2.find('option').attr('selected', true);
$select2.find('option').trigger('change.select2');
}
});
+1
i have one select2 refreshing other select2 like this
function bindOtherSelect2(e) {
//SAVES SELECTED ID
var id = (e.params.data.id);
//AJAX CALL
$.ajax({
url: "/Controller/Method",
type: "POST",
dataType: "json",
data: { id: id },
success: function (result) {
$("#select2Id").html('');
$("#select2Id").select2({ data: result});
}
});
};
I would love to set back the placeholder but i didnt manage to do that, hope this helps someone.
I don't understand why this wasn't labeled as critical, because it's a pretty crucial feature. You should be able to update any options without having to destroy the select2.
If you initialise your select2 instance with the data property set, you can use the following to add new items:
var items = [{
id: 123,
text: 'Item 1'
}];
var $someDropdown = $('#some_dropdown');
// Clear out existing options
$someDropdown.html('');
var dataAdapter = $someDropdown.data('select2').dataAdapter;
dataAdapter.addOptions(dataAdapter.convertToOptions(items));
The simple jQuery plugin created from this thread:
(function ($) {
$.fn.refreshDataSelect2 = function (data) {
this.select2('data', data);
// Update options
var $select = $(this[1]);
var options = data.map(function(item) {
return '<option value="' + item.id + '">' + item.text + '</option>';
});
$select.html(options.join('')).change();
};
})(jQuery);
Use:
var data = [{ id: 1, text: 'some value' }];
$('.js-some-field').refreshDataSelect2(data);
The simple jQuery plugin created from this thread:
…
Thank you, nice plugin ! 😃 I had to change your $(this[1]) to $(this[0]), though
Something like this:
var dataAppleDevices = [{id: 1, text: "iPhone"}, {id: 2, text: "iPad"}, {id: 3, text: "iPod"}];
var dataSamsungDevices = [{id: 1, text: "Galaxy S"}, {id: 2, text: "Galaxy Tab"}, {id: 3, text: "Galaxy A"}];
var select = $("yourSelect");
select.select2({
placeholder: "Choose your device",
allowClear: true,
data: dataAppleDevices
});
<working...>
select.select2().empty();
select.append("<option></option>"); // for placeholder
select.select2({
placeholder: "Choose your device",
allowClear: true,
data: dataSamsungDevices
});
Hello,
Anyone has a workaround that really works for these kinds of case?
I tried all the suggestions but nothing works yet.
I have 2 filters, one by Date, one by Timing. I want to be able to refresh Timing based on the Date chosen. Sounds simple enough, but can't get it to work with Select2. Both get data from arrays.
This is my code:
$( "#time_search" ).select2("destroy").html("");
jQuery( "#time_search" ).append("");
jQuery( "#time_search" ).select2({
placeholder: "Select a timing",
allowClear: true,
data: my_arr
});
I also tried empty():
$( "#time_search" ).select2("destroy").empty();
Didn't work either.
The 2 filters at initialization:

After Date div is being selected, and Timing div being refreshed:

From developer's tool, I can see that that size of the drop down is reduced to 1px after Select2 being reset. I tried to input an array of string, but the size is still 1px.

Any thought how to get this fixed? :(. Love this JS and hope to be able to fix. Thanks a lot.
Per documentation found at https://select2.github.io/options.html:
$('select').select2({
data: [
{
id: 'value',
text: 'Text to display'
},
// ... more data objects ...
]
});
With that I was able to use something to the effect of:
<select id="my-select" class="select2_single">...</select>
...
// This var would be retrieved from an outside source
var dataArrayFromAJAX = [{ id: 'foo', text: 'bar' }];
$('#my-select').html('').select2({
data: [ dataArrayFromAJAX ]
});
It replaced existing elements. Or to keep existing options from elements
// Get existing elements
var oldDataArray = [ ];
$('#my-select option').each(function(idx,element) {
oldDataArray.push( { id: element.value, text: element.innerHTML } );
});
// Merge existing and new elements and refresh select2
$('#my-select').html('').select2({
data: [ oldDataArray.concat(dataArrayFromAJAX) ]
});
element.val("");
element.find('option').remove();
$.each(data, function(index, value) {
element.append('<option value="' + value.id + '">' + value.id + '</option>');
});
I do like that. And if u use multiple select2. U can add below line after appending.
element.select2({
multiple: true,
});
And final event use that.
element.val('').trigger('change');
Cool Stuff @renandecarlo
Hello
I found this way.
$('#descJugador').select2('val', this.id);
$('#descJugador').select2('data').disabled = false;
$('#descJugador').select2('data', null);
If you do that, the select2 refresh the value dynamically.
@dejan9393 wins the day!
If you're using a custom templateSelection and/or templateResult with Ajax data that has custom properties (such as the GitHub repository example in the docs), you can't just add an , because your custom templates will be missing all of the required data!
Here's a slight variation... Adds a single option to the list and selects it. (Note, this works with the AJAX adapter too.)
`var items = {
id: "345", //Important
fullName: "Justin Jones",
title: "Analyst",
country: "Australia"
}
//First, add an option to the select.
var dataAdapter = $('#my-dropdown').data('select2').dataAdapter;
var option = dataAdapter.option(item);
dataAdapter.addOptions(option);
//Set the value of the control and trigger an update
$('#my-dropdown').val(item.id);
$('#my-dropdown').trigger("change");`
It took me a while to find this issue. Could the technique provided by @dejan9393 please be added to the documentation?
I think it needs to go under Programmatic Control, "Add, select, or clear items".
There's another technique for adding custom data to dynamically added options mentioned
on Stackoverflow, which approximates to:
$("#my-dropdown").append(new Option(...)).select2("data")[0].customparam='abc'
@dejan9393 wins the day!
If you're using a custom templateSelection and/or templateResult with Ajax data that has custom properties (such as the GitHub repository example in the docs), you can't just add an asdf, because your custom templates will be missing all of the required data!
Here's a slight variation... Adds a single option to the list and selects it. (Note, this works with the AJAX adapter too.)
`var items = {
id: "345", //Important
fullName: "Justin Jones",
title: "Analyst",
country: "Australia"
}//First, add an option to the select.
var dataAdapter = $('#my-dropdown').data('select2').dataAdapter;
var option = dataAdapter.option(item);
dataAdapter.addOptions(option);//Set the value of the control and trigger an update
$('#my-dropdown').val(item.id);
$('#my-dropdown').trigger("change");`
This is the real and only solution!!! great job!!
Is there a hope Select2 will get its API act together one day?
Most helpful comment
I have a working workaround (dirty add-hoc solution, but it works).