select2 not displaying selected value text added programatically - javascript

I have a dropdown created with select2 (v4.0.13 and I can not change it) using AJAX requests on a form where the user can search for things. The page is built with Thymeleaf and when the view is reloaded the dropdown value is lost.
Following the recommendation of the documentation itself when you deal with AJAX values, I have writed this code:
let selectedOption = $('#select2-id');
$.ajax({
type: 'GET',
dataType: 'json',
url: baseAjaxUrl + '/api_endpoint?q=' + myVar,
}).then(function (data) {
if (data.length !== 0) {
let optionValues = data[0];
let option = new Option(optionValues.name, optionValues.id, true, true);
selectedOption.append(option).trigger('change.select2');
selectedOption.trigger({
type: 'select2:select',
params: {data: optionValues}
});
}
});
Now, when the view is reloaded the dropdown has the value but does not show its text. An x appears to remove it and if you hover the mouse over it in the tooltip the text that should be displayed in the dropdown appears.
In the <span> generated by select2 I can see the title attribute with the value that should be displayed:
<span class="select2-selection__rendered" id="select2-anId-container" role="textbox" aria-readonly="true" title="The text that should be displayed">
<span class="select2-selection__clear" title="Remove all items" data-select2-id="20">×</span>
</span>
The select2 is initialised as follows:
$('#select2-id').select2({
ajax: {
url: baseAjaxUrl + '/api_endpoint',
dataType: 'json',
delay: 180,
data: function (parameters) {
return {
q: parameters.term,
page: parameters.page
};
},
processResults: function (data, page) {
return {
results: data
};
}
},
placeholder: {
id: "-1",
text: "Select an item"
},
allowClear: true,
escapeMarkup: function (markup) {
return markup;
},
minimumInputLength: 5,
templateResult: formatItem,
templateSelection: formatItemSelection,
theme: "bootstrap",
width: myCustomWidth
});
What is the problem or what have I done wrong?
Greetings.

After finding this answer, my problem was that when selecting an option, templateSelection is used. Checking the function I realised that the object I receive has the fields id and name. The object that handles select2 also has the fields id and name but it has another one, text, and this is the one it uses to show the value!
So in the function I use for templateSelection I have to do:
if (data.text === "") {
data.text = data.name;
}
... other stuff ...
return data.text;
Done!

Related

How to include a label in jQuery Select2?

I've set up a Select2 instance that queries my database and renders the results via AJAX on an input that the user has access to.
Everything is working but as this is a location selection input for a user and there are districts and municipalities with same names, for example, I want to add a label for each result to identify them either as "District", "Municipality", "Parish", etc. but I'm unable to do so, I've been unable to find any support on this matter on the Internet and the extension itself doesn't seem to be able to do this,
Select2 AJAX Function
$("#location-property-alert-location").select2({
placeholder: "Type the name of the location",
minimumInputLength: 2,
ajax: {
url: '/ajax/search-locations-by-query',
dataType: 'json',
type: "GET",
data: function data(params) {
return {
query: params.term // search term
};
},
processResults: function processResults(response) {
// return{
// results: response.name
// };
response = response.map(function (item) {
// console.log(item);
return {
id: JSON.stringify(item), // json_encode the data so we can pass this through the ID
code: JSON.stringify(item),
test: "hello",
text: item.location_name
};
});
console.log(response);
return {
results: response
};
},
cache: true
}
});
I know Select2 can take additional data parameters such as the code and test parameters I added above but I don't know how exactly I can use these to create elements within the results with each item's category, for example, as portrayed in the screenshot below.
Each item's category is being stringified so I can pass this data through the form's submission either way but I need to identify each item's category on the frontend for the user to be able to differentiate locations,
Anyone has any idea on how to do this?
Cheers
Note: I don't want Select2's label appearance which basically groups options per category.
You can use templateSelection which will format your selection appearance and then change the result according to your json data.
Below is the demo for how this works with random json data.
function formatResult(item) {
//checks if the id present or not
if (!item.id) {
return item.text;
}
//return the format options..
var element = $(`<span>${item.text}<span class="text_small">${item.username}</span></span>'`)
return element;
};
$("#location-property-alert-location").select2({
placeholder: "Type the name of the location",
minimumInputLength: 2,
ajax: {
url: 'https://jsonplaceholder.typicode.com/users', //this is just for demo...
dataType: 'json',
type: "GET",
data: function data(params) {
return {
query: params.term // search term
};
},
processResults: function processResults(response) {
response = response.map(function(item) {
return {
id: JSON.stringify(item.id),
text: item.name,
username: item.username //pass here extra param
};
});
return {
results: response
};
},
cache: true
},
templateResult: formatResult //your selection format
});
.text_small {
font-size: 10px;
color: grey;
margin-left: 10px;
}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2#4.1.0-beta.1/dist/css/select2.min.css">
<script src="https://code.jquery.com/jquery-3.5.0.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2#4.1.0-beta.1/dist/js/select2.min.js"></script>
<select id="location-property-alert-location" style="width:300px"></select>

Select2 ajax: preselected data in edit mode

I'm making user profile page on Laravel and using select2 component to filter huge list of items.
I have a ajax-based select2. It's good when you are on /create page, but I need to have selected value in it, when I am on page /edit/1.
$('.search-filter-ajax').select2({
width: '100%',
minimumInputLength: 3,
placeholder: "Search...",
ajax: {
url: '/api/listing/search/',
data: function (term) {
return {
data: term.term
};
},
processResults: function (data) {
return {
results: $.map(data, function (item) {
return {
text: item.name,
search_from: item.name,
model: 'some_model',
id: item.id
}
})
};
},
dataType: 'json',
type: "GET",
delay: 250,
},
});
I tried to use initSelection function, but no luck, because it creates only select2 text elements, when I need real <option value="1"> something </option> component.
initSelection: function (element, callback) {
var id = $(element).data('select-id');
var text = $(element).data('select-text');
callback({ id: id, text: text });
},
How can I have a valid preselected option in select2 on page load, but still having opportunity to fire ajax call by onChange?
well, you could try to use your own logic to generate slect options like
$.ajax().then((res)=>{
$('#select').html('');
res.data.forEach((item)={$('#select').append($('option').text(item.text).value(item.value);)})
})

xeditable & select2 dropdown w/ajax source displaying empty after submitting

I've gotten xeditable and select2 to work with an api call as the source and everything works great EXCEPT the following.
After submitting the select2 dropdown, the value of the table is displayed as EMPTY and requires a page refresh in order to update to the correct value.
Does anyone know how to update the value to the selected select2 dropdown value?
my html:
<td class="eo_role"><a href="#" data-pk={{r.pk}} data-type="select2" data-url="/api/entry/{{r.pk}}/"
data-name="eo_role" data-title="Enter EO_role">{{r.eo_role}}</a></td>
here is my JS:
$('#example .eo_role a').editable( {
params: function(params) { //params already contain `name`, `value` and `pk`
var data = {};
data[params.name] = params.value;
return data;
},
source: 'http://localhost:8000/api/eo_role/select_two_data/',
tpl: '<select></select>',
ajaxOptions: {
type: 'put'
},
select2: {
cacheDatasource:true,
width: '150px',
id: function(pk) {
return pk.id;
},
ajax: {
url: 'http://localhost:8000/api/eo_role/select_two_data/',
dataType: "json",
type: 'GET',
processResults: function(item) {return item;}
}
},
formatSelection: function (item) {
return item.text;
},
formatResult: function (item) {
return item.text;
},
templateResult: function (item) {
return item.text;
},
templateSelection : function (item) {
return item.text;
},
});
Again - everything works (database updates, dropdownlist populates etc.) however the <td> gets updated with "EMPTY" after submitting the dropdown - requiring a page refresh to show the correct value.
I figured out a workaround. I'm SUPER PUMPED.
//outside of everything, EVERYTHING
//test object is a global holding object that is used to hold the selection dropdown lists
//in order to return the correct text.
var test = {};
$('#example .eo_role a').editable( {
params: function(params) { //params already contain `name`, `value` and `pk`
var data = {};
data[params.name] = params.value;
return data;
},
//MUST be there - it won't work otherwise.
tpl: '<select></select>',
ajaxOptions: {
type: 'put'
},
select2: {
width: '150px',
//tricking the code to think its in tags mode (it isn't)
tags:true,
//this is the actual function that triggers to send back the correct text.
formatSelection: function (item) {
//test is a global holding variable set during the ajax call of my results json.
//the item passed here is the ID of selected item. However you have to minus one due zero index array.
return test.results[parseInt(item)-1].text;
},
ajax: {
url: 'http://localhost:8000/api/eo_role/select_two_data/',
dataType: "json",
type: 'GET',
processResults: function(item) {
//Test is a global holding variable for reference later when formatting the selection.
//it gets modified everytime the dropdown is modified. aka super convenient.
test = item;
return item;}
}
},
});
I faced that same issue. I handle it that way:
In x-editable source code look for:
value2html: function(value, element) {
var text = '', data,
that = this;
if(this.options.select2.tags) { //in tags mode just assign value
data = value;
//data = $.fn.editableutils.itemsByValue(value, this.options.select2.tags, this.idFunc);
} else if(this.sourceData) {
data = $.fn.editableutils.itemsByValue(value, this.sourceData, this.idFunc);
} else {
//can not get list of possible values
//(e.g. autotext for select2 with ajax source)
}
As you can see, there is else statment, without any code (only 2 comments) that is the situation, with which we have a problem. My solution is to add missing code:
(...) else {
//can not get list of possible values
//(e.g. autotext for select2 with ajax source)
data = value;
}
That's fix problem without tags mode enabled. I do not detect any unwanted behaviors so far.
Example code:
jQuery('[data-edit-client]').editable({
type: 'select2',
mode: 'inline',
showbuttons: false,
tpl: '<select></select>',
ajaxOptions: {
type: 'POST'
},
select2: {
width: 200,
multiple: false,
placeholder: 'Wybierz klienta',
allowClear: false,
formatSelection: function (item) {
//test is a global holding variable set during the ajax call of my results json.
//the item passed here is the ID of selected item. However you have to minus one due zero index array.
return window.cacheData[parseInt(item)].text;
},
ajax: {
url: system.url + 'ajax/getProjectInfo/',
dataType: 'json',
delay: 250,
cache: false,
type: 'POST',
data: {
projectID: system.project_id,
action: 'getProjectClients',
customer: parseInt(jQuery("[data-edit-client]").attr("data-selected-company-id"))
},
processResults: function (response) {
window.cacheData = response.data.clients;
return {
results: response.data.clients
};
}
}
}
});

Select2 4.0 initial value in ajax mode

I have the following select on my page:
<select><option value="1" selected="selected">Caption</option></select>
I call select2 (v 4.0) init:
city.select2({
ajax: {
url: <...>,
data: <...>,
processResults: <...>,
cache: true
},
escapeMarkup: function(markup){ return markup; },
minimumInputLength: 0,
templateResult: function(repo){ return repo.name; },
templateSelection: function(repo){ return repo.name; }
});
The problem is that select2 is resetting default selected value and showing blank string. Is there any way to set default value on select2 init?
The issue was in your templateSelection method, as you are expecting a name property to be on your data object. Aside from the fact that text is now required and you wouldn't need the method if you re-mapped it, you aren't handling the case where the data object has a text property.
city.select2({
ajax: {
url: <...>,
data: <...>,
processResults: <...>,
cache: true
},
escapeMarkup: function(markup){ return markup; },
minimumInputLength: 0,
templateResult: function(repo){ return repo.name || repo.text; },
templateSelection: function(repo){ return repo.name || repo.text; }
});
This should fix your issue and display the initial selections properly.
The select2 docs now have an example of how to do this.
// Set up the Select2 control
$('#mySelect2').select2({
ajax: {
url: '/api/students'
}
});
// Fetch the preselected item, and add to the control
var studentSelect = $('#mySelect2');
$.ajax({
type: 'GET',
url: '/api/students/s/' + studentId
}).then(function (data) {
// create the option and append to Select2
var option = new Option(data.full_name, data.id, true, true);
studentSelect.append(option).trigger('change');
// manually trigger the `select2:select` event
studentSelect.trigger({
type: 'select2:select',
params: {
data: data
}
});
});
Basically, configure select2 for ajax and then pre-fill with the desired object. The magic is done in the last bit, .trigger() which causes select2 to pick up the change and render it.

How to set Select2 value using initSelection?

I am using jQuery Select2 for dropdown lists. The data is loading via AJAX call using in JSON format.
Here is my script:
$("#sub_lessons").select2({
maximumSelectionSize: 1,
placeholder: "Select Sublessons",
allowClear: true,
multiple:true,
ajax: {
url: "getData.action?lid="+lessonid,
dataType: 'json',
data: function (term, page) {
return {
q: term
};
},
results: function (data, page) {
return { results: data };
}
}
});
My html snippet:
<input type="hidden" id="sub_lessons" style="width:300px"/>
When we clicking on the select2 box the data is loading perfectly,
but I have the function like setValue() when button is clicked.
<input type="button" onclick="setValue(1)"/>
And my function is:
function setValue(no)
{
$('#sub_lessons').select2('val',no);
}
But the value is not being set. I searched in some sites and suggested to use initselection.I used initselection,but it does not work.please help me how to set value to select2 when button is pressed.
any help would be appreciated.
try something like this
$('#sub_lessons').select2('val','no');
I try this; work for me. You should add this to initSelection select2:
initSelection: function (element, callback) {
var id = $(element).val();
$.ajax("url/" + id, {
dataType: "json"
}).done(function (data) {
var newOption = new Option(data.title, data.id, true, true);
$('#sub_lessons').append(newOption).trigger('change');
callback({"text": data.title, "id": data.id});
});
},

Categories