How can I set the initial value of Select2 when using AJAX?

142,953

Solution 1

You are doing most things correctly, it looks like the only problem you are hitting is that you are not triggering the change method after you are setting the new value. Without a change event, Select2 cannot know that the underlying value has changed so it will only display the placeholder. Changing your last part to

.val(initial_creditor_id).trigger('change');

Should fix your issue, and you should see the UI update right away.


This is assuming that you have an <option> already that has a value of initial_creditor_id. If you do not Select2, and the browser, will not actually be able to change the value, as there is no option to switch to, and Select2 will not detect the new value. I noticed that your <select> only contains a single option, the one for the placeholder, which means that you will need to create the new <option> manually.

var $option = $("<option selected></option>").val(initial_creditor_id).text("Whatever Select2 should display");

And then append it to the <select> that you initialized Select2 on. You may need to get the text from an external source, which is where initSelection used to come into play, which is still possible with Select2 4.0.0. Like a standard select, this means you are going to have to make the AJAX request to retrieve the value and then set the <option> text on the fly to adjust.

var $select = $('.creditor_select2');

$select.select2(/* ... */); // initialize Select2 and any events

var $option = $('<option selected>Loading...</option>').val(initial_creditor_id);

$select.append($option).trigger('change'); // append the option and update Select2

$.ajax({ // make the request for the selected data object
  type: 'GET',
  url: '/api/for/single/creditor/' + initial_creditor_id,
  dataType: 'json'
}).then(function (data) {
  // Here we should have the data object
  $option.text(data.text).val(data.id); // update the text that is displayed (and maybe even the value)
  $option.removeData(); // remove any caching data that might be associated
  $select.trigger('change'); // notify JavaScript components of possible changes
});

While this may look like a lot of code, this is exactly how you would do it for non-Select2 select boxes to ensure that all changes were made.

Solution 2

What I've done is more clean and needs to make two arrays :

  • one contains a list of Object with id and a text (in my case its id and name, depending of your templateResult) (its what you get from ajax query)
  • the second is only an array of ids (selection value)

I initialize select2 using the first array as data, and the second as the val.

An example function with as parameters a dict of id:name.

function initMyList(values) {
    var selected = [];
    var initials = [];

    for (var s in values) {
        initials.push({id: s, name: values[s].name});
        selected.push(s);
    }

    $('#myselect2').select2({
        data: initials,
        ajax: {
            url: "/path/to/value/",
            dataType: 'json',
            delay: 250,
            data: function (params) {
                return {
                    term: params.term,
                    page: params.page || 1,
                };
            },
            processResults: function (data, params) {
                params.page = params.page || 1;

                return {
                    results: data.items,
                    pagination: {
                        more: (params.page * 30) < data.total_count
                    }
                };
            },
            cache: true
        },
        minimumInputLength: 1,
        tokenSeparators: [",", " "],
        placeholder: "Select none, one or many values",
        templateResult: function (item) { return item.name; },
        templateSelection: function (item) { return item.name; },
        matcher: function(term, text) { return text.name.toUpperCase().indexOf(term.toUpperCase()) != -1; },
    });

    $('#myselect2').val(selected).trigger('change');
}

You can feed the initials value using ajax calls, and use jquery promises to do the select2 initialization.

Solution 3

It's works for me ...

Don't use jQuery, only HTML: Create the option value you will display as selected. If ID it's in select2 data it will selected automatically.

<select id="select2" name="mySelect2">
  <option value="mySelectedValue">
        Hello, I'm here!
  </option>
</select>

Select2.org - Default Pre Selected values

Solution 4

One scenario that I haven't seen people really answer, is how to have a preselection when the options are AJAX sourced, and you can select multiple. Since this is the go-to page for AJAX preselection, I'll add my solution here.

$('#mySelect').select2({
    ajax: {
        url: endpoint,
        dataType: 'json',
        data: [
            { // Each of these gets processed by fnRenderResults.
                id: usersId,
                text: usersFullName,
                full_name: usersFullName,
                email: usersEmail,
                image_url: usersImageUrl,
                selected: true // Causes the selection to actually get selected.
            }
        ],
        processResults: function(data) {

            return {
                results: data.users,
                pagination: {
                    more: data.next !== null
                }
            };

        }
    },
    templateResult: fnRenderResults,
    templateSelection: fnRenderSelection, // Renders the result with my own style
    selectOnClose: true
}); 

Solution 5

The issue of being forced to trigger('change') drove me nuts, as I had custom code in the change trigger, which should only trigger when the user changes the option in the dropdown. IMO, change should not be triggered when setting an init value at the start.

I dug deep and found the following: https://github.com/select2/select2/issues/3620

Example:

$dropDown.val(1).trigger('change.select2');

Share:
142,953

Related videos on Youtube

Greg
Author by

Greg

Updated on November 20, 2021

Comments

  • Greg
    Greg over 2 years

    I have a select2 v4.0.0 being populated from an Ajax array. If I set the val of the select2 I can see via javascript debugging that it has selected the correct item (#3 in my case), however this is not shown in the select box, it is still showing the placeholder. enter image description here

    Whereas I should be seeing something like this: enter image description here

    In my form fields:

    <input name="creditor_id" type="hidden" value="3">
    <div class="form-group minimal form-gap-after">
        <span class="col-xs-3 control-label minimal">
            <label for="Creditor:">Creditor:</label>
        </span>
        <div class="col-xs-9">
            <div class="input-group col-xs-8 pull-left select2-bootstrap-prepend">
                <select class="creditor_select2 input-xlarge form-control minimal select2 col-xs-8">
                    <option></option>
                </select>
            </div>
        </div>
    </div>
    

    My javascript:

    var initial_creditor_id = "3";
    $(".creditor_select2").select2({
        ajax: {
           url: "/admin/api/transactions/creditorlist",
           dataType: 'json',
           delay: 250,
           data: function (params) {
               return {
                    q: params.term,
                    c_id: initial_creditor_id,
                    page: params.page
               };
           },
           processResults: function (data, page) {
                return {
                    results: data
                };
           },
           cache: true
       },
       placeholder: "Search for a Creditor",
       width: "element",
       theme: "bootstrap",
       allowClear: true
       }).on("select2:select", function (e) {
          var selected = e.params.data;
          if (typeof selected !== "undefined") {
               $("[name='creditor_id']").val(selected.creditor_id);
               $("#allocationsDiv").hide();
               $("[name='amount_cash']").val("");
               $("[name='amount_cheque']").val("");
               $("[name='amount_direct']").val("");
               $("[name='amount_creditcard']").val("");
            }
        }).on("select2:unselecting", function (e) {
            $("form").each(function () {
                this.reset()
            });
            ("#allocationsDiv").hide();
            $("[name='creditor_id']").val("");
        }).val(initial_creditor_id);
    

    How can I make the select box show the selected item rather than the placeholder? Should I be sending this as part of the AJAX JSON response perhaps?

    In the past, Select2 required an option called initSelection that was defined whenever a custom data source was being used, allowing for the initial selection for the component to be determined. This worked fine for me in v3.5.

  • Greg
    Greg about 9 years
    That almost works. The DataObject returned is likely to be an array of objects with a single item in it, so for a single item I probably need to return something like: $option.text(data[0].text).val(data[0].id); or if I am getting back an array of all of the possible options: if (initial_creditor_id >0) { var initial = jQuery.grep(data, function (selected) { return selected.creditor_id == initial_creditor_id }); $option.text(initial[0].text); $option.val(initial[0].creditor_id);
  • user396404
    user396404 almost 9 years
    Any idea how to preselect multiple options for multi select boxes?
  • Kevin Brown-Silva
    Kevin Brown-Silva almost 9 years
    @user396404 the same concepts should apply, just pass a list of ids into val() instead of a single id. Or just append multiple <option selected> and that should be handled automatically.
  • user2808054
    user2808054 over 8 years
    Hi - what is '#status' ? shouldthat be '#test' ?
  • Jean-Paul
    Jean-Paul over 8 years
    select2 has the option to .select2("val", value); this should do exactly the same as you do only much shorter, am i right?
  • Kevin Brown-Silva
    Kevin Brown-Silva over 8 years
    @JpHouten select2('val') is deprecated, but it previously worked the exact same as the first code snippet in this answer.
  • Jean-Paul
    Jean-Paul over 8 years
    @KevinBrown Thank you, I guess you already fixed this issue for me in github.com/select2/select2/issues/4035 (if thats you) I only added a new problem i stumbled across while heavily testing this.
  • Clint
    Clint almost 8 years
    I realize this answer is over a year old, but the documentation for Select2 for the FAQ question: "How can I set the initially selected options when using AJAX?" still points to this. I've attached a JSFiddle as a working example for v4.0.3 jsfiddle.net/57co6c95
  • jiaweizhang
    jiaweizhang almost 8 years
    This is definitely the better way of doing it. Manipulating the DOM by adding <option> doesn't seem to be the most logical way to do it. This is how I do it in 4.0
  • ClearBoth
    ClearBoth almost 8 years
    I need help with this! the docs redirected me here and now stuck! I'm using 4.0.3. I want to do for multiple one
  • userlond
    userlond almost 8 years
    @firebird631, your solution is brilliant, it works and very big thanks!
  • Jimmy Ilenloa
    Jimmy Ilenloa over 7 years
    this is the cleanest solution i have seen so far
  • ClearBoth
    ClearBoth over 7 years
    There is a problem. What if I want to request more than just id and text? I have tried but the data option only getting the data for templateResult and ignore it for templateSelection. Any idea?
  • Kevin Brown-Silva
    Kevin Brown-Silva over 7 years
    I will note that internally the data option is just generating <option> tags and adding them to the select. This answer doesn't cover how you handle cases where you need to go out to an API to get more information, but I guess that's a less typical case.
  • Sahin Yanlık
    Sahin Yanlık over 7 years
    Hello with ajax I am not able to do it. When I send a list with two object there is no problem it tries to insert those two object but only one inserted. and already selected automatically. I never able to see two option, even I sent two item.
  • Carlos Mora
    Carlos Mora about 7 years
    Great idea for a generic initialisation procedure.
  • shanabus
    shanabus about 7 years
    @ClearBoth I was able to find a solution with using templateSelection's and having an initial selection. See my answer below - stackoverflow.com/a/43942110/88732
  • HTMLGuy
    HTMLGuy almost 7 years
    FINALLY!!!!! Wow, that could not have been more frustrating!! I had been using "name" instead of "text" and it was killing me. I switched to the default "text" key and it's working perfectly now. Thank you!
  • Alisson Reinaldo Silva
    Alisson Reinaldo Silva almost 6 years
    @KevinBrown I think it would be awesome if Select2 had an option to fetch initial options by using the own select2's config during setup, as if the user had clicked the dropdown to show initial available options. In this example, the selected Id would be sent with the request to fetch this initial data, so the server could handle and load just the selected option. I think this would be better than making an ajax call manually, as the component would be already prepared to send the appropriate request data, transform the response and apply any templates.
  • Alisson Reinaldo Silva
    Alisson Reinaldo Silva almost 6 years
    Also, I tried this solution, but unfortunately after calling $select.trigger('change'); the option is still with the Loading... text, even though data.text had exactly the text I wanted. Maybe this is no longer supported in 4.0.6.
  • Vitalij
    Vitalij almost 6 years
    You are defying the whole meaning of using remote data fetching using query! 99.99% of the time people will use data fetching when they handle a lot of options and need to save traffic and memory, and your idea to pre-select few values is first to fetch everything and save that in memory...
  • Vitalij
    Vitalij almost 6 years
    I guess you are saving not only a select value, but also a text to your database, so you can retrieve it like that... sheesh!
  • Marcio Mazzucato
    Marcio Mazzucato almost 6 years
    @ITDesigns.eu, I don't think so, the value sento to database is initial-value and the text Initial text act as a placeholder, it isn't sent to database. It is working in my application.
  • Vitalij
    Vitalij almost 6 years
    why would I need a placeholder instead of a real text in the actual option?!
  • Marcio Mazzucato
    Marcio Mazzucato almost 6 years
    @ITDesigns.eu, Select2 catches this info and mount itself
  • Loenix
    Loenix over 2 years
    You are missing selected attribute. And this is not working well with custom rendering.