[jquery] Update select2 data without rebuilding the control

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.

enter image description here

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

The answer is


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:

  • can handle selectors that return multiple instances
  • use the existing select2's instance options (default) or pass in a new set of options
  • keep any already-selected values (default) that are still valid, or clear them entirely
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:

  1. When Template is rendered...
  2. Init a select2 control with data from Session.
  3. @autorun (this.autorun) function runs every time the value of Session.get("select2Data") changes.
  4. Whenever Session changes, clear existing select2 options and re-create with new data.

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.


Examples related to jquery

How to make a variable accessible outside a function? Jquery assiging class to th in a table Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Getting all files in directory with ajax Bootstrap 4 multiselect dropdown Cross-Origin Read Blocking (CORB) bootstrap 4 file input doesn't show the file name Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource how to remove json object key and value.?

Examples related to jquery-select2

How can I set the initial value of Select2 when using AJAX? Dynamically add item to jQuery Select2 control that uses AJAX How to set selected value of jquery select2? Styling of Select2 dropdown select boxes How to use placeholder as default value in select2 framework How can I disable selected attribute from select2() dropdown Jquery? Select2 open dropdown on focus How to use Select2 with JSON via Ajax request? Select2() is not a function jQuery select2 get value of select tag?

Examples related to ui-select2

How to get Selected Text from select2 when using <input> How do I change selected value of select2 dropdown with JqGrid? Update select2 data without rebuilding the control set the width of select2 input (through Angular-ui directive) Is there a SELECT ... INTO OUTFILE equivalent in SQL Server Management Studio? Can I apply the required attribute to <select> fields in HTML5? jQuery UI tabs. How to select a tab based on its id not based on index How To Get Selected Value From UIPickerView UIButton: set image for selected-highlighted state How can I pass selected row to commandLink inside dataTable or ui:repeat?