Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing Options Dynamically #2830

Closed
abhillman opened this issue Nov 25, 2014 · 63 comments
Closed

Changing Options Dynamically #2830

abhillman opened this issue Nov 25, 2014 · 63 comments
Labels

Comments

@abhillman
Copy link

@abhillman abhillman commented Nov 25, 2014

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?

@kevin-brown
Copy link
Member

@kevin-brown kevin-brown commented Nov 26, 2014

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.

@kevin-brown kevin-brown added this to the 4.0 milestone Nov 26, 2014
@ova2
Copy link

@ova2 ova2 commented Feb 17, 2015

Is it now possible to change options (add, remove) dynamically? What is the API for that?

@kevin-brown
Copy link
Member

@kevin-brown kevin-brown commented Feb 18, 2015

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...

  • Current instance options are retrieved
  • Options are augmented as requested
  • Instance is destroyed
  • Instance is re-initialized with the modified options

Which probably isn't that difficult, but I currently do not have the time to investigate the drawbacks or alternatives.

@kevin-brown kevin-brown removed this from the 4.0 milestone Feb 18, 2015
@ova2
Copy link

@ova2 ova2 commented Feb 19, 2015

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);
@jogaco
Copy link

@jogaco jogaco commented Feb 26, 2015

+1 for a placeholder API

@razakj
Copy link

@razakj razakj commented Mar 30, 2015

+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();
@benrosati
Copy link

@benrosati benrosati commented May 21, 2015

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"]);
@sdhull
Copy link

@sdhull sdhull commented Oct 16, 2015

+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.

@Myrdivar
Copy link

@Myrdivar Myrdivar commented Oct 22, 2015

+1 for this feature. It's common to alter the content of a dropdown dynamically and with the previous verion I had no problem.

@lvecchio
Copy link

@lvecchio lvecchio commented Oct 23, 2015

+1 for this feature as well.

@voidale
Copy link

@voidale voidale commented Oct 31, 2015

+1

@hems
Copy link

@hems hems commented Nov 2, 2015

Isn't it possible to make a workaround "query" function? If so, any drawbacks ?

  • Keep the options for each select on javascript objects
  • Don't add the "" to the selects
  • Use the query method to dynamically populate the options when user clicks ( even if zero characters typed )
  • Check the state of the application
  • Render options accordingly ?

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.

@IgorDobryn
Copy link

@IgorDobryn IgorDobryn commented Nov 3, 2015

+1

@benoittgt
Copy link

@benoittgt benoittgt commented Nov 5, 2015

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.

@renandecarlo
Copy link

@renandecarlo renandecarlo commented Nov 24, 2015

Just use change().

$('#myselect').html('<option>Whatever</option>').change()
@benoittgt
Copy link

@benoittgt benoittgt commented Nov 24, 2015

Thanks @renandecarlo

@baabaaox
Copy link

@baabaaox baabaaox commented Nov 28, 2015

$('#txtClassTeacher').html("<option value='"+res.source.id+"'></option>");
$('#select2-txtClassTeacher-container').text(res.source.truename);
@mustafaaloko
Copy link

@mustafaaloko mustafaaloko commented Feb 29, 2016

+1

@glowysourworm
Copy link

@glowysourworm glowysourworm commented Apr 2, 2016

+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....

@jvq2
Copy link

@jvq2 jvq2 commented Apr 27, 2016

+1 The inability to dynamically change/disable options is definitely a major deal.

@Cartman34
Copy link

@Cartman34 Cartman34 commented Dec 15, 2016

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.

@gracecarey
Copy link

@gracecarey gracecarey commented Dec 15, 2016

+1

@Zxurian
Copy link

@Zxurian Zxurian commented Dec 16, 2016

@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.

@trevithj
Copy link

@trevithj trevithj commented Jan 18, 2017

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. :)

@brunocascio
Copy link

@brunocascio brunocascio commented Feb 2, 2017

Which is the status of this?

@emielmolenaar
Copy link

@emielmolenaar emielmolenaar commented Feb 21, 2017

+100

@rborosak
Copy link

@rborosak rborosak commented Feb 22, 2017

+1

1 similar comment
@sannek8552
Copy link

@sannek8552 sannek8552 commented Feb 22, 2017

+1

@mktcode
Copy link

@mktcode mktcode commented Mar 1, 2017

+1 But can anyone tell me if there is something wrong with @renandecarlo 's solution? Seems to work quite well.

@Zxurian
Copy link

@Zxurian Zxurian commented Mar 1, 2017

+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.

@trevithj
Copy link

@trevithj trevithj commented Mar 2, 2017

@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();
@Zxurian
Copy link

@Zxurian Zxurian commented Mar 2, 2017

@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);
@wreardan
Copy link

@wreardan wreardan commented Mar 14, 2017

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!!

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');
	}
});
@ivofsp
Copy link

@ivofsp ivofsp commented Mar 24, 2017

+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.

@alenb
Copy link

@alenb alenb commented Mar 27, 2017

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.

@dejan9393
Copy link

@dejan9393 dejan9393 commented Apr 5, 2017

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));
@nilov
Copy link

@nilov nilov commented Apr 7, 2017

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);
@not-a-lot
Copy link

@not-a-lot not-a-lot commented Apr 25, 2017

The simple jQuery plugin created from this thread:

Thank you, nice plugin ! 😃 I had to change your $(this[1]) to $(this[0]), though

@hixel
Copy link

@hixel hixel commented May 4, 2017

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 
});
@lg134
Copy link

@lg134 lg134 commented Jul 31, 2017

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:
screen shot 2017-07-31 at 10 25 33 pm
After Date div is being selected, and Timing div being refreshed:
screen shot 2017-07-31 at 10 25 51 pm

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.
screen shot 2017-07-31 at 10 26 31 pm

Any thought how to get this fixed? :(. Love this JS and hope to be able to fix. Thanks a lot.

@isaiahgrant
Copy link

@isaiahgrant isaiahgrant commented Aug 8, 2017

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) ]
});
@VuQuang
Copy link

@VuQuang VuQuang commented Jan 26, 2018

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');

@alexkiburu
Copy link

@alexkiburu alexkiburu commented Mar 13, 2018

Cool Stuff @renandecarlo

@GeraElem
Copy link

@GeraElem GeraElem commented Mar 13, 2018

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.

@phillanier
Copy link

@phillanier phillanier commented Nov 11, 2018

@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");`

@rohanc
Copy link

@rohanc rohanc commented Jul 5, 2019

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'

@lorife
Copy link

@lorife lorife commented May 20, 2020

@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!!

@temuri416
Copy link

@temuri416 temuri416 commented Dec 6, 2020

Is there a hope Select2 will get its API act together one day?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet