I am converting an <input type="hidden">
to a select2 dropdown and feeding it data through the query method
$('#inputhidden').select2({
query: function( query ) {
query.callback( data ); // the data is in the format select2 expects and all works well..
);
});
The problem is i needed to hack the select2 UI and position two buttons on top of the search bar that, when clicked, will perform ajax calls and will have to update the select2 content.
Now, I need those updates to occur without rebuilding the select2 entirely but rather just refreshing the items on the dropdown. I cannot find a way to pass a new set of data to an already created select2 control, is that possible ?
This question is related to
jquery
jquery-select2
ui-select2
For Select2 4.X
var instance = $('#select2Container').data('select2');
var searchVal = instance.dropdown.$search.val();
instance.trigger('query', {term:searchVal});
As best I can tell, it is not possible to update the select2 options without refreshing the entire list or entering some search text and using a query function.
What are those buttons supposed to do? If they are used to determine the select options, why not put them outside of the select box, and have them programmatically set the select box data and then open it? I don't understand why you would want to put them on top of the search box. If the user is not supposed to search, you can use the minimumResultsForSearch option to hide the search feature.
Edit: How about this...
HTML:
<input type="hidden" id="select2" class="select" />
Javascript
var data = [{id: 0, text: "Zero"}],
select = $('#select2');
select.select2({
query: function(query) {
query.callback({results: data});
},
width: '150px'
});
console.log('Opening select2...');
select.select2('open');
setTimeout(function() {
console.log('Updating data...');
data = [{id: 1, text: 'One'}];
}, 1500);
setTimeout(function() {
console.log('Fake keyup-change...');
select.data().select2.search.trigger('keyup-change');
}, 3000);
Example: Plunker
Edit 2: That will at least get it to update the list, however there is still some weirdness if you have entered search text before triggering the keyup-change
event.
I solved this issue by using the ajax option and specifying a custom transport function.
see this fiddle Select2 dynamic options demo
Here is the relevant js to get this to work.
var $items = [];
let options = {
ajax: {
transport: function(params, success, failure) {
let items = $items;
if (params.data && params.data.q) {
items = items.filter(function(item) {
return new RegExp(params.data.q).test(item.text);
});
}
let promise = new Promise(function(resolve, reject) {
resolve({
results: items
});
});
promise.then(success);
promise.catch(failure);
}
},
placeholder: 'Select item'
};
$('select').select2(options);
let count = $items.length + 1;
$('button').on('click', function() {
$items.push({
id: count,
text: 'Item' + count
});
count++;
});
Try this one:
var data = [{id: 1, text: 'First'}, {id: 2, text: 'Second'}, {...}];
$('select[name="my_select"]').empty().select2({
data: data
});
I think it suffices to hand the data over directly:
$("#inputhidden").select2("data", data, true);
Note that the second parameter seems to indicate that a refresh is desired.
Thanks to @Bergi for help with this.
If that doesn't automatically update you could either try calling it's updateResults method directly.
$("#inputhidden").select2("updateResults");
Or trigger it indirectly by sending a trigger to the "input.select2-input" like so:
var search = $("#inputhidden input.select2-input");
search.trigger("input");
Diego's comment on the answer given by SpinyMan is important because the empty()
method will remove the select2 instance, so any custom options will no longer be retained. If you want to keep existing select2 options you must save them, destroy the existing select2 instance, and then re-initialize. You can do that like so:
const options = JSON.parse(JSON.stringify(
$('#inputhidden').data('select2').options.options
));
options.data = data;
$('#inputhidden').empty().select2('destroy').select2(options);
I would recommend to always explicitly pass the select2 options however, because the above only copies over simple options and not any custom callbacks or adapters. Also note that this requires the latest stable release of select2 (4.0.13 at the time of this post).
I wrote generic functions to handle this with a few features:
function select2UpdateOptions(
selector,
data,
newOptions = null,
keepExistingSelected = true
) {
// loop through all instances of the matching selector and update each instance
$(selector).each(function() {
select2InstanceUpdateOptions($(this), data, newOptions, keepExistingSelected);
});
}
// update an existing select2 instance with new data options
function select2InstanceUpdateOptions(
instance,
data,
newOptions = null,
keepSelected = true
) {
// make sure this instance has select2 initialized
// @link https://select2.org/programmatic-control/methods#checking-if-the-plugin-is-initialized
if (!instance.hasClass('select2-hidden-accessible')) {
return;
}
// get the currently selected options
const existingSelected = instance.val();
// by default use the existing options of the select2 instance unless overridden
// this will not copy over any callbacks or custom adapters however
const options = (newOptions)
? newOptions
: JSON.parse(JSON.stringify(instance.data('select2').options.options))
;
// set the new data options that will be used
options.data = data;
// empty the select and destroy the existing select2 instance
// then re-initialize the select2 instance with the given options and data
instance.empty().select2('destroy').select2(options);
// by default keep options that were already selected;
// any that are now invalid will automatically be cleared
if (keepSelected) {
instance.val(existingSelected).trigger('change');
}
}
var selBoxObj = $('#selectpill');
selBoxObj.trigger("change.select2");
Using Select2 4.0 with Meteor you can do something like this:
Template.TemplateName.rendered = ->
$("#select2-el").select2({
data : Session.get("select2Data")
})
@autorun ->
# Clear the existing list options.
$("#select2-el").select2().empty()
# Re-create with new options.
$("#select2-el").select2({
data : Session.get("select2Data")
})
What's happening:
This works for any reactive data source - such as a Collection.find().fetch() - not just Session.get().
NOTE: as of Select2 version 4.0 you must remove existing options before adding new onces. See this GitHub Issue for details. There is no method to 'update the options' without clearing the existing ones.
The above is coffeescript. Very similar for Javascript.
Source: Stackoverflow.com