Reputation: 1853
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.
Whereas I should be seeing something like this:
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.
Upvotes: 114
Views: 171993
Reputation: 412
I'm Using Select2 V 4.0.13
I found a workable solution for the ones looking for selecting a specific option by value
.
Note that I commented my ajax request because it's my personal webpage and StackOverflow is not allowed, but you can put your own request url in data-requesturl
select attribute and uncomment ajax in js part. Remember to return array with [{"id":"id","text":"text"}]
structure.
I used another ajax because I don't wanted select2 requests every search or paginate, that's a solution to get data before and use transport
with server data.
The most important part is to put selected value in data-value
select attribute, and then it will be selected.
var ssTimerObj = {};
$('.SelectSearch').each(function () {
var ssSelector = $(this),
ssID = $(this).attr('id');
if(!$(ssSelector).hasClass('Lazy')){
$(ssSelector).select2({
dropdownParent: $(ssSelector).parent(),
allowClear: true
});
} else {
ssTimerObj[ssID] = null;
var requestURL = $(ssSelector).attr('data-requesturl'),
requestParameters = $(ssSelector).attr('data-requestparameters'),
placeholder = $(ssSelector).attr('data-placeholder'),
value = $(ssSelector).attr('data-value'),
pageSize = $(ssSelector).attr('data-pagesize');
requestParameters = requestParameters === undefined ? '' : requestParameters;
requestParameters = requestParameters.replace(/'/g, '"');
requestParameters = requestParameters !== '' ? JSON.parse(requestParameters) : {};
placeholder = placeholder === undefined ? '' : placeholder;
value = value === undefined ? '' : value;
pageSize = pageSize === undefined ? 0 : pageSize;
pageSize = parseInt(pageSize, 10);
data = JSON.parse('[{"id":"nsalazar","text":"Nelly Salazar Mori"},{"id":"mtriguero","text":"Marta Triguero Consentino"},{"id":"ddiaz","text":"David D\u00edaz De Mier"},{"id":"vlopez","text":"Ver\u00f3nica L\u00f3pez Mart\u00edn"},{"id":"esanchez","text":"Eduardo S\u00e1nchez Rodr\u00edguez"},{"id":"mgraca","text":"M\u00f3nica Graca "}]');
/*$.ajax({
data: requestParameters,
url: requestURL,
type: 'POST',
beforeSend: function () {},
success: function (data) {
*/
var dataSelect = data;
$(ssSelector).html('');
$(ssSelector).select2({
dropdownParent: $(ssSelector).parent(),
allowClear: true,
placeholder: placeholder,
ajax: {
delay: 250,
transport: function(params, success, failure) {
var term = params.data.term != undefined ? params.data.term.toLowerCase() : '';
var page = params.data.page != undefined ? params.data.page : 1;
if (ssTimerObj[ssID]){
clearTimeout(ssTimerObj[ssID]);
}
ssTimerObj[ssID] = setTimeout(function(){
ssTimerObj[ssID] = null;
var results = dataSelect // your base array here
.filter(function(f){
// your custom filtering here.
return f.text !== undefined ? f.text.toLowerCase().includes(term) : true;
})
.map(function(f){
// your custom mapping here.
return { id: f.id, text: f.text};
});
var paged = results.slice((page -1) * pageSize, page * pageSize);
var options = {
results: paged,
pagination: {
more: results.length >= page * pageSize
}
};
success(options);
}, params.delay);
}
}
});
if(value !== ''){
var selectedData = dataSelect.filter(function(f){
return f.id !== undefined ? (f.id === value ? true : false) : false;
});
if(selectedData.length > 0){
$(ssSelector).select2("trigger", "select", {
data: { id: selectedData[0]['id'], text: selectedData[0]['text'] }
});
}
}
/*
},
error: function (error) {
console.log(error);
}
});
*/
}
});
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>
<div class="row m-3">
<div class="col-sm-12">
<label for="User">Select Valued</label>
<select class="form-control SelectSearch Lazy" name="User" id="User" data-placeholder="--Seleccione--" data-requesturl="[RequestURL for example: /GetUserList]" data-pagesize="60" data-value="nsalazar">
<option value="">Cargando...</option>
</select>
</div>
<div class="col-sm-12 mt-2">
<label for="User2">Select Normal</label>
<select class="form-control SelectSearch Lazy" name="User2" id="User2" data-placeholder="--Seleccione--" data-requesturl="[RequestURL for example: /GetUserList]" data-pagesize="60">
<option value="">Cargando...</option>
</select>
</div>
</div>
Upvotes: 0
Reputation: 11
Easiest Solution ever
$(document).ready(function(){
$("#allowed_products").select2({
ajax: {
url: "/factory/get_product_list",
dataType: 'json',
type: "POST",
// Additional AJAX parameters go here; see the end of this chapter for the full code of this example
data: function (params) {
var query = {
search: params.term,
csrfmiddlewaretoken: `${$("input[name=csrfmiddlewaretoken]").val()}`
}
return query;
},
delay: 250,
processResults: function(data) {
return {
results: data.products
};
},
cache: true,
},
placeholder: "Select products",
dropdownParent: $("#edit-product")
})
$.ajax({
url: `/user/to/selectedProducts`,
type: "POST",
data: {
"params": {}
},
success: function (data) {
let selectElement = $("#allowed_products");
$.each(data.selected_products, function(index, obj) {
var option = new Option(obj.text, obj.id, true, true);
selectElement.append(option).trigger("change");
});
},
error: function (error) {
console.log(error)
}
});
});
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" />
<label for="limit">Allowed Products</label>
<select id="allowed_products" class="select2 select2-multiple" multiple data-placeholder="Search product" tabindex="-1" aria-hidden="true" name="product" required>
<option value=""></option>
</select>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>
Add the selected (default) value to the select2 dropdown as an option and mark then selected
so that select2() considers it select and when by Ajax a new list of options of the dropdown is loaded, merges the new options with the already selected option.
Thus it causes no conflict with the already selected option.
Upvotes: 1
Reputation: 149
This is the solution that worked for me for multiple + template :
(my ajax return an additional parameter, "email")
// my template
var my_template_func = function (data){
if( data.email )
var email = data.email;
else if( data.element )
var email = data.element.dataset.email;
var html = '<span><span>'+data.text+'</span> - <em>'+email+'</em></span>';
return $(html);
};
// select2 init
$('.my-select').select2({
ajax: {
url: '...',
dataType: 'json',
},
templateResult: my_template_func,
templateSelection: my_template_func,
});
Then either i set default option(s) in html
<option value="555" data-email="[email protected]" selected>Bob</option>
Or i add the option(s) with JS
// add option(s)
var option = new Option('Bob', 555, true, true);
option.dataset.email = '[email protected]';
$('.my-select').append(option).trigger('change');
Upvotes: 0
Reputation: 21
https://github.com/select2/select2/issues/4272
only this solved my problem.
even you set default value by option, you have to format the object, which has the text attribute and this is what you want to show in your option.
so, your format function have to use ||
to choose the attribute which is not empty.
Upvotes: 2
Reputation: 323
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
Upvotes: 12
Reputation: 9295
For a simple and semantic solution i prefer to define the initial value in HTML, example:
<select name="myfield" data-placeholder="Select an option">
<option value="initial-value" selected>Initial text</option>
</select>
So when i call $('select').select2({ ajax: {...}});
the initial value is initial-value
and its option text is Initial text
.
My current Select2 version is 4.0.3, but i think it has a great compatibility with other versions.
Upvotes: 2
Reputation: 13115
If you are using a templateSelection and ajax, some of these other answers may not work. It seems that creating a new option
element and setting the value
and text
will not satisfy the template method when your data objects use other values than id and text.
Here is what worked for me:
$("#selectElem").select2({
ajax: { ... },
data: [YOUR_DEFAULT_OBJECT],
templateSelection: yourCustomTemplate
}
Check out the jsFiddle here: https://jsfiddle.net/shanabus/f8h1xnv4
In my case, I had to processResults
in since my data did not contain the required id
and text
fields. If you need to do this, you will also need to run your initial selection through the same function. Like so:
$(".js-select2").select2({
ajax: {
url: SOME_URL,
processResults: processData
},
data: processData([YOUR_INIT_OBJECT]).results,
minimumInputLength: 1,
templateSelection: myCustomTemplate
});
function processData(data) {
var mapdata = $.map(data, function (obj) {
obj.id = obj.Id;
obj.text = '[' + obj.Code + '] ' + obj.Description;
return obj;
});
return { results: mapdata };
}
function myCustomTemplate(item) {
return '<strong>' + item.Code + '</strong> - ' + item.Description;
}
Upvotes: 6
Reputation: 749
Create simple ajax combo with de initial seleted value for select2 4.0.3
<select name="mycombo" id="mycombo""></select>
<script>
document.addEventListener("DOMContentLoaded", function (event) {
selectMaker.create('table', 'idname', '1', $("#mycombo"), 2, 'type');
});
</script>
library .js
var selectMaker = {
create: function (table, fieldname, initialSelected, input, minimumInputLength = 3, type ='',placeholder = 'Select a element') {
if (input.data('select2')) {
input.select2("destroy");
}
input.select2({
placeholder: placeholder,
width: '100%',
minimumInputLength: minimumInputLength,
containerCssClass: type,
dropdownCssClass: type,
ajax: {
url: 'ajaxValues.php?getQuery=true&table=' + table + '&fieldname=' + fieldname + '&type=' + type,
type: 'post',
dataType: 'json',
contentType: "application/json",
delay: 250,
data: function (params) {
return {
term: params.term, // search term
page: params.page
};
},
processResults: function (data) {
return {
results: $.map(data.items, function (item) {
return {
text: item.name,
id: item.id
}
})
};
}
}
});
if (initialSelected>0) {
var $option = $('<option selected>Cargando...</option>').val(0);
input.append($option).trigger('change'); // append the option and update Select2
$.ajax({// make the request for the selected data object
type: 'GET',
url: 'ajaxValues.php?getQuery=true&table=' + table + '&fieldname=' + fieldname + '&type=' + type + '&initialSelected=' + initialSelected,
dataType: 'json'
}).then(function (data) {
// Here we should have the data object
$option.text(data.items[0].name).val(data.items[0].id); // update the text that is displayed (and maybe even the value)
$option.removeData(); // remove any caching data that might be associated
input.trigger('change'); // notify JavaScript components of possible changes
});
}
}
};
and the php server side
<?php
if (isset($_GET['getQuery']) && isset($_GET['table']) && isset($_GET['fieldname'])) {
//parametros carga de petición
parse_str(file_get_contents("php://input"), $data);
$data = (object) $data;
if (isset($data->term)) {
$term = pSQL($data->term);
}else{
$term = '';
}
if (isset($_GET['initialSelected'])){
$id =pSQL($_GET['initialSelected']);
}else{
$id = '';
}
if ($_GET['table'] == 'mytable' && $_GET['fieldname'] == 'mycolname' && $_GET['type'] == 'mytype') {
if (empty($id)){
$where = "and name like '%" . $term . "%'";
}else{
$where = "and id= ".$id;
}
$rows = yourarrayfunctionfromsql("SELECT id, name
FROM yourtable
WHERE 1 " . $where . "
ORDER BY name ");
}
$items = array("items" => $rows);
$var = json_encode($items);
echo $var;
?>
Upvotes: 0
Reputation: 96
after spending a few hours searching for a solution, I decided to create my own. He it is:
function CustomInitSelect2(element, options) {
if (options.url) {
$.ajax({
type: 'GET',
url: options.url,
dataType: 'json'
}).then(function (data) {
element.select2({
data: data
});
if (options.initialValue) {
element.val(options.initialValue).trigger('change');
}
});
}
}
And you can initialize the selects using this function:
$('.select2').each(function (index, element) {
var item = $(element);
if (item.data('url')) {
CustomInitSelect2(item, {
url: item.data('url'),
initialValue: item.data('value')
});
}
else {
item.select2();
}
});
And of course, here is the html:
<select class="form-control select2" id="test1" data-url="mysite/load" data-value="123"></select>
Upvotes: 1
Reputation: 91
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
});
Upvotes: 7
Reputation: 73
I am adding this answer mainly because I can't comment above! I found it was the comment by @Nicki and her jsfiddle, https://jsfiddle.net/57co6c95/, that eventually got this working for me.
Among other things, it gave examples of the format for the json needed. The only change I had to make was that my initial results were returned in the same format as the other ajax call so I had to use
$option.text(data[0].text).val(data[0].id);
rather than
$option.text(data.text).val(data.id);
Upvotes: 0
Reputation: 569
What I've done is more clean and needs to make two arrays :
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.
Upvotes: 35
Reputation: 4782
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');
Upvotes: 7
Reputation: 359
Hi was almost quitting this and go back to select 3.5.1. But finally I got the answer!
$('#test').select2({
placeholder: "Select a Country",
minimumResultsForSearch: 2,
ajax: {
url: '...',
dataType: 'json',
cache: false,
data: function (params) {
var queryParameters = {
q: params.term
}
return queryParameters;
},
processResults: function (data) {
return {
results: data.items
};
}
}
});
var option1 = new Option("new",true, true);
$('#status').append(option1);
$('#status').trigger('change');
Just be sure that the new option is one of the select2 options. I get this by a json.
Upvotes: -4
Reputation: 41671
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.
Upvotes: 118