Programmatically set the value of a Select2 ajax
Asked Answered
S

14

41

I have a Select2 auto-complete input (built via SonataAdmin), but cannot for the life of me figure out how to programmatically set it to a known key/value pair.

There's a JS Fiddle here that shows roughly what I have. What I want to know is what function I can attach to the button so that

  • the Select2 field shows the text "NEW VALUE" to the user, and
  • the Select2 field will submit a value of "1" when the form is sent to the server

I have tried all sorts of combinations of jQuery and Select2 data and val methods, called against various inputs on the page, but nothing seems to work... surely there's some way to do this?

-- Edit --

The accepted answer below is very useful, helps shed some light on the right way to initialise the selection and explains what initSelection is for.

Having said that, it seems that my biggest mistake here was the way I was trying to trigger the change.

I was using:

$(element).select2('data', newObject).trigger('change');

But this results in an empty add object inside select2's change event.

If, instead, you use:

$(element).select2('data', newObject, true);

then the code works as it should, with the newObject available in select2's change event and the values being set correctly.

I hope this extra information helps somebody else!

Stuppy answered 20/8, 2014 at 1:28 Comment(0)
T
28

Note: The Question and this Answer are for Select2 v3. Select2 v4 has a very different API than v3.

I think the problem is the initSelection function. Are you using that function to set the initial value? I know the Select2 documentation makes it sound like that is it's purpose, but it also says "Essentially this is an id->object mapping function," and that is not how you have implemented it.

For some reason the call to .trigger('change') causes the initSelection function to get called, which changes the selected value back to "ENABLED_FROM_JS".

Try getting rid of the initSelection function and instead set the initial value using:

autocompleteInput.select2('data', {id:103, label:'ENABLED_FROM_JS'});

jsfiddle

Note: The OP has supplied the formatResult and formatSelection options. As supplied, those callback functions expect the items to have a "label" property, rather than a "text" property. For most users, it should be:

autocompleteInput.select2('data', {id:103, text:'ENABLED_FROM_JS'});

More info on the initSelection function:

If you search through the Select2 documentation for "initSelection", you will see that it is used when the element has an initial value and when the element's .val() function is called. That is because those values consist of only an id and Select2 needs the entire data object (partly so it can display the correct label).

If the Select2 control was displaying a static list, the initSelection function would be easy to write (and it seems like Select2 could supply it for you). In that case, the initSelection function would just have to look up the id in the data list and return the corresponding data object. (I say "return" here, but it doesn't really return the data object; it passes it to a callback function.)

In your case, you probably don't need to supply the initSelection function since your element does not have an initial value (in the html) and you are not going to call its .val() method. Just keep using the .select2('data', ...) method to set values programmatically.

If you were to supply an initSelection function for an autocomplete (that uses ajax), it would probably need to make an ajax call to build the data object.

Tatiania answered 20/8, 2014 at 2:43 Comment(5)
By the way, is there any documentation of what it means by "Essentially this is an id->object mapping function" (and how to use it in that context for an autocomplete field)?Stuppy
initSelection is Deprecated in Select2 4.0. This has been replaced by the current method on the data adapter and is only available in the full builds.Damper
please update the fiddle - it fails with 404 on resource loadingSergias
@Sergias - I updated the URLs for the external resources in the jsfiddle, but I don't think it ever actually functioned because the ajax call is not valid.Tatiania
so in order to set value you need 'text' property to set a label or else the value you set would not display the label. but what if the data that in the 'text' property is from database, so you need another ajax call to get the name/text of specific id. the code become redundant because the select2 itself has ajax call and you need another ajax call to get the value of text and select2 doesnt provide proper method to set value.Vallee
P
68

Note this was tested with version 4+

I was finally able to make progress after finding this discussion: https://groups.google.com/forum/#!topic/select2/TOh3T0yqYr4

The last comment notes a method that I was able to use successfully.

Example:

$("#selectelement").select2("trigger", "select", {
    data: { id: "5" }
});

This seems to be enough information for it to match the ajax data, and set the value correctly. This helped immensely with Custom Data Adapters.


Note: For multi select, execute the above code for each item, like this :

  // for each initially selected ids, execute the above code to add the id to the selection.
  [{id: 5, text: 'op5'}, {id: 10, text: 'op10'}].forEach(option => {
    $("#selectelement").select2("trigger", "select", {data: { id: option.id, text: option.text }});
  })
Pratfall answered 18/7, 2016 at 22:9 Comment(5)
Just as a note, this will set <option> tag with minimal information, but you can use $("#selectelement").select2("data") to get the full object's values. This was enough for me, but otherwise, you should modify the above to also return "text" in addition to "id".Pratfall
works in v4. found this after 2 days of googling, scouring the docs etc.Frag
Thanks! Their docs says to use new Option but that doesn't works for AJAX calls with custom templatingSolenoid
It works but When I tried to select about 30 select2 elements with this method it took like 5 or 6 seconds. I have a form where there array of items so while editing that form selecting additional attributes with this method took time so didn't work for me.Resale
The documentation on select2.org/programmatic-control/… do have an example now that is similar to this original answer, but with a slightly different syntax. selectElement.trigger({ type: 'select2:select', params: { data: data } });Pratfall
T
28

Note: The Question and this Answer are for Select2 v3. Select2 v4 has a very different API than v3.

I think the problem is the initSelection function. Are you using that function to set the initial value? I know the Select2 documentation makes it sound like that is it's purpose, but it also says "Essentially this is an id->object mapping function," and that is not how you have implemented it.

For some reason the call to .trigger('change') causes the initSelection function to get called, which changes the selected value back to "ENABLED_FROM_JS".

Try getting rid of the initSelection function and instead set the initial value using:

autocompleteInput.select2('data', {id:103, label:'ENABLED_FROM_JS'});

jsfiddle

Note: The OP has supplied the formatResult and formatSelection options. As supplied, those callback functions expect the items to have a "label" property, rather than a "text" property. For most users, it should be:

autocompleteInput.select2('data', {id:103, text:'ENABLED_FROM_JS'});

More info on the initSelection function:

If you search through the Select2 documentation for "initSelection", you will see that it is used when the element has an initial value and when the element's .val() function is called. That is because those values consist of only an id and Select2 needs the entire data object (partly so it can display the correct label).

If the Select2 control was displaying a static list, the initSelection function would be easy to write (and it seems like Select2 could supply it for you). In that case, the initSelection function would just have to look up the id in the data list and return the corresponding data object. (I say "return" here, but it doesn't really return the data object; it passes it to a callback function.)

In your case, you probably don't need to supply the initSelection function since your element does not have an initial value (in the html) and you are not going to call its .val() method. Just keep using the .select2('data', ...) method to set values programmatically.

If you were to supply an initSelection function for an autocomplete (that uses ajax), it would probably need to make an ajax call to build the data object.

Tatiania answered 20/8, 2014 at 2:43 Comment(5)
By the way, is there any documentation of what it means by "Essentially this is an id->object mapping function" (and how to use it in that context for an autocomplete field)?Stuppy
initSelection is Deprecated in Select2 4.0. This has been replaced by the current method on the data adapter and is only available in the full builds.Damper
please update the fiddle - it fails with 404 on resource loadingSergias
@Sergias - I updated the URLs for the external resources in the jsfiddle, but I don't think it ever actually functioned because the ajax call is not valid.Tatiania
so in order to set value you need 'text' property to set a label or else the value you set would not display the label. but what if the data that in the 'text' property is from database, so you need another ajax call to get the name/text of specific id. the code become redundant because the select2 itself has ajax call and you need another ajax call to get the value of text and select2 doesnt provide proper method to set value.Vallee
C
11

Be carreful, there is a mistake in "validated" comment.

autocompleteInput.select2('data', {id:103, label:'ENABLED_FROM_JS'});

The correct way is

autocompleteInput.select2('data', {id:103, text:'ENABLED_FROM_JS'});

Use text instead of label

Cartercarteret answered 14/1, 2015 at 23:38 Comment(2)
For me it was name instead of text/label :)Toms
If you look at the OP's jsfiddle, you will see the OP is supplying the formatResult and formatSelection options. The way those functions are written, they expect the items to have a "label" property, not a "text" property. I have added to my answer to make this clear to others.Tatiania
I
11

To set initial values you need to add the necessary options tag to the select element with jQuery, then define these options as selected with select2's val method and finally trigger select2's 'change' event.

1.-$('#selectElement').append('<option value=someID>optionText</option>');
2.-$('#selectElement').select2('val', someID, true);

The third boolean argument tells select2 to trigger the change event.

For more info, see https://github.com/select2/select2/issues/3057

Imprescriptible answered 25/8, 2015 at 11:23 Comment(1)
You can't use a select element for remote data (ajax).Hannan
L
10

With Select2 version 4+, there is actually nothing special you need to do. Standard jQuery with a 'change' event trigger at the end will work.

var $select = $("#field");
var items = {id: 1, text: "Name"}; // From AJAX etc
var data = $select.val() || [];    // If you want to merge with existing

$(items).each(function () {
  if(!$select.find("option[value='" + this.id + "']").length) {
    $select.append(new Option(this.text, this.id, true, true));
  }
  data.push(this.id);
});

$select.val(data).trigger('change'); // Standard event notifies select2

There is a basic example in the Select2 documentation: https://select2.org/programmatic-control/add-select-clear-items

Lysimeter answered 5/3, 2018 at 6:11 Comment(0)
S
3

from their examples https://select2.github.io/examples.html

Programmatic access:

var $example = $(".js-example-programmatic").select2();
var $exampleMulti = $(".js-example-programmatic-multi").select2();
$(".js-programmatic-set-val").on("click", function () { $example.val("CA").trigger("change"); });
$(".js-programmatic-open").on("click", function () { $example.select2("open"); });
$(".js-programmatic-close").on("click", function () { $example.select2("close"); });
$(".js-programmatic-init").on("click", function () { $example.select2(); });
$(".js-programmatic-destroy").on("click", function () { $example.select2("destroy"); });
$(".js-programmatic-multi-set-val").on("click", function () { $exampleMulti.val(["CA", "AL"]).trigger("change"); });
$(".js-programmatic-multi-clear").on("click", function () { $exampleMulti.val(null).trigger("change"); });
Swizzle answered 9/12, 2015 at 15:12 Comment(0)
S
2

All you have to do is set the value and then execute: $ ('#myselect').select2 (); or $ ('select').select2 ();. And everything is updated very well.

Springhalt answered 5/3, 2017 at 16:29 Comment(0)
D
1

If you remove the .trigger('change') from your fiddle it logs Object {id: 1, label: "NEW VALUE"} (need to click twice since the logging is before the value change). Is that what you're looking for?

Domeniga answered 20/8, 2014 at 2:17 Comment(2)
Yes, I removed the .trigger('change');, too, and it just worked for me (Chrome)Alexi
Unfortunately I need to trigger the change, and JohnS's answer gets to the root of the problem so I have accepted that answer instead.Stuppy
J
1

When using select2 with multiple option, use this construction:

$(element).select2("data", $(element).select2("data").concat(newObject), true);

Juliojulis answered 6/8, 2015 at 13:29 Comment(0)
H
1

this is it:

$("#tag").select2('data', { id:8, title: "Hello!"});
Heydon answered 28/10, 2016 at 20:35 Comment(0)
V
1

Append a new option with id and text

let $newOption = $("<option selected='selected'></option>").val(1).text('New Text goes here');
$("#selector").append($newOption).trigger('change');
Vial answered 28/12, 2021 at 16:50 Comment(0)
P
0

FOR VERSION 3.5.3

    $(".select2").select2('data',{id:taskid,text:taskname}).trigger('change');

Based on John S' answer . Just the the above will work however only if while initializing the select2 the initSelection option is not initialized.

$(".select2").select2({
      //some setup
})
Pejsach answered 19/7, 2016 at 17:26 Comment(0)
W
0

For those still using version 3.5 or even higher ones. Please be sure how you reference select2.js to your page. If you are using async or defer load. This plug-in might behave differently.

Thought to mention.

Wollastonite answered 15/1, 2019 at 3:9 Comment(0)
F
0

In my situation I was able to render the preselected option into the HTML server side with PHP.

During my page load, I already knew the option value, so my <select name="team_search"></select> became the following;

        <select name="team_search">
            <?php echo !empty($preselected_team) 
                    ? '<option selected="selected" value="'. $preselected_team->ID .'">' . $preselected_team->team_name . '</option>' 
                    : null ?>
        </select>';

As you can see, when I have a $preselected_team available I render in an option with the selected attribute, value and label set. And, if I don't have a value then not option is rendered.

This approach may not always be possible (and in the case of the OP is not mentioned), but it does come with the added benefit of being ready on page load ahead of JavaScript execution.

Fled answered 13/4, 2019 at 14:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.