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 · 65 comments
Closed

Changing Options Dynamically #2830

abhillman opened this issue Nov 25, 2014 · 65 comments

Comments

@abhillman
Copy link

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

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

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 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 commented Feb 26, 2015

+1 for a placeholder API

@razakj
Copy link

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

@benilla
Copy link

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

+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

+1 for this feature as well.

@markudevelop
Copy link

+1

@hems
Copy link

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

+1

@benoittgt
Copy link

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

Just use change().

$('#myselect').html('<option>Whatever</option>').change()

@benoittgt
Copy link

Thanks @renandecarlo

@baabaaox
Copy link

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

@mustafaaloko
Copy link

+1

@glowysourworm
Copy link

+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 commented Apr 27, 2016

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

@trevithj
Copy link

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

Which is the status of this?

@emielmolenaar
Copy link

+100

@rborosak
Copy link

+1

1 similar comment
@sannek8552
Copy link

+1

@mktcode
Copy link

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

@adorbabble
Copy link

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

Cool Stuff @renandecarlo

@GeraElem
Copy link

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

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

@barzanraza
Copy link

var dataCategory = JSON.parse(sessionStorage.getItem('category'));
var select = $("#category");

select.select2({
    tags: true,
    allowClear: true,
    maximumInputLength: 30,
    maximumSelectionLength: 20,
    tokenSeparators: [',', ' '],
    data: dataCategory 
}).on("change", function (e) {

    var selected = []; // create an array to hold all currently wrote by user

    // loop through each option
    $('#category option').each(function() {
        // if it's selected, add it to the array above
        if (this.selected) {
            selected.push(this.value);
        }
    });


    // store the array of selected options
    sessionStorage.setItem('category', JSON.stringify(selected));

});


// set and show the previous wrote keywords
var dataCategoryLength = dataCategory.length;
for (var i =0; i < dataCategoryLength; i++) {
   
    $('#category').val(dataCategory).trigger('change');

}

@ojopaul
Copy link

ojopaul commented Nov 11, 2021

`// get your data ready
var data = [];

// get the target id
var $select = $('#subcategory');

// reset the whole html of the id with jquery
$select.html('');

// loop through the new option populated with prepared data
for(var i = 0; i < = data.length; i++){
    $select.append("<option value=\"" + data[i].value + "\">" + data[i].name + "</option>");
}

// here's my full code while working with laravel
$("#categories").change(function () {
    var val = $(this).val();

    $.ajax({
        url: "{{ url('/company_user/job/post/get_sub_category') }}?cat_id=" + $(this).val(),
        method: 'GET',
        success: function(jobSubCategories) {
        //    alert(jobSubCategories.length)

        var $select = $('#subcategory');

        $select.html('');

        for(var i=0; i<=jobSubCategories.length; i++){
            $select.append("<option value=\"" + jobSubCategories[i].id + "\">" + jobSubCategories[i].name + "</option>");
        }


        },
        error: function (data) {
            console.log(data)
        }
    });`

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

No branches or pull requests