I have script which does ajax call and sets values using x-editable and select2, when I select data from list which is loaded and click ok the data is not updated on UI, it keep saying it is empty.
Here is my function
$('#ActFilter').editable({
type: 'select2',
title: 'Act',
placement: 'right',
select2: {
cacheDataSource: false,
allowClear: true,
multiple: false,
tokenSeparators: [",", " "],
minimumResultsForSearch: 1,
initSelection: function (element, callback) {
return $.get('rest/qualityActsCode', {
query: element.val()
}, function (data) {
self.cacheDataSource = data;
if (element.val() != "") {
var id = element.val();
filteredData = new Array();
for (var i = 0; i < data.length; i++) {
if (data[i].id == id) {
filteredData.push(data[i]);
break;
}
}
callback(filteredData);
}
});
},
query: function(query) {
self = this;
var key = query.term;
var cachedData = self.cacheDataSource;
if(cachedData) {
query.callback({results: cachedData});
return;
} else {
$.ajax({
url: 'rest/qualityActsCode',
data: { q : query.term },
dataType: 'json',
type: 'GET',
success: function(data) {
self.cacheDataSource = data;
query.callback({results: data});
}
});
}
}
},
url: function (a, v) {
$('#ActValue').val(a.value);
}
});
X-editable expects your ajax data to be returned in the json format of:
{id: 1, text: "myexample"}
The text key is displayed on the ui.
The id key is sent to the server on submit.
In case, your ajax calls returns information that deviates from the above standard, you have to reformat the data in the results function.
Below is a full blown example that you can use to run select2 in ajax mode:
$('#my-x-editable-element').editable({
//If there is no selected item, the placeholder will be displayed on the select2 element
placeholder: "Select a customer",
//Send data to server, upon submit (i.e on click of the tick button)
onblur: 'submit',
//VERY IMPORTANT: set to the url where you will fetch the data.
//The request URL to the server would then be the following format: "/ajaxsearch/customercode?term=searchtext&limit=10&page=1&_=1440047016963"
//Parameter explanation(can be customized in the data section below):
//Term = the term typed in the select2 box. Use this value to search your database
//Limit = How many items select2 is expecting in your return call. Use this to limit your query results
//Page = select2's current page. Use this value to calculate the offset of your query.
source: '/ajaxsearch/customercode',
//Define your select2 options, It is compatible with most select 3.x options
select2: {
allowClear: false,
minimumInputLength: 3,
//IMPORTANT: set the id from your ajax result.
id: function (item) {
return item.id;
},
//IMPORTANT: Customize your ajax calls
ajax: {
//Url to the ajax call. Notice that it is the same as the 'source' option above. Both have the same purpose. Don't ask why.
url: "/ajaxsearch/customercode",
//Data type you are expecting in return
dataType: "json",
//The amount of time after typing a new term, that select2 will wait, before sending a new ajax request
quietMillis: 500,
//Query parameters send to the server on ajax calls. Customize as necessary.
data: function (term, page) {
return {
term: term,
limit: 10,
page: page
};
},
//IMPORTANT
//Results function: Used to customize the array of data received from the server.
//#param {data} array response from the ajax call
//#param {page} int current page number - select2 pagination
//#return {object}
//return value X-editable, expected two keys at the top level of the array: 'results' and 'more'
//'results' is an array of items from your recent query.
//'more' is a boolean. It informs x-editable if there is more information that can be queried from your database. If it is true, select2 will send a new query to the database while scrolling the list of items.
results: function (data, page){
//Calculation to determine if there is more information that can be queried
//Based on the total count of rows from the database, current page, and limit of items per page(in this case, 10).
var more = (page * 10) < data.total
//If query returned some results, we map it in an x-editable compatible format.
//Array format MUST contain the 'id' and 'text' keys.
if(data.total > 0)
{
var mycustomarray;
mycustomarray = $.map(data.customers, function (item) {
return {
id: item.code,
name: item.name,
text: item.name+" (Code:"+item.code+")"
}
});
return {results: mycustomarray, more:more};
}
else
{
//If there are no results, return empty array, as shown below
return {results: ''};
}
},
},
//IMPORTANT
//Format Selection function
//Used for display purposes, i.e the text that x-editable shows after the x-editable has been submitted.
//If x-editable fails to get the text, 'empty' will be shown on submit.
//#param {object} item currently selected item on the select2 list
//#return {string}
formatSelection: function (item) {
return item.text;
},
//Init Selection function
//Used for initializing the x-editable object if there is already a value present on document load.
//#param {object} element jQuery current x-editable element
//#param {function} callback function to set default values
initSelection: function (element, callback) {
callback({id: element.val() , text: element.parents('div.editable-select2').children('a.editable').html()});
}
}
})
There is issue on x-editable using select2 latest version. i suggest you use version 4.0.0 of select2. refer to this link: https://github.com/vitalets/x-editable/issues/882
Related
I am trying to attach AJAX fetched value with Select2. My JavaScript code is like below.
(function($) {
$(document).ready(function() {
$(".volunteer").on("click", function (event) {
let element_id = event.target.id;
// Check if select is already loaded
if (!$(this).has("select").length) {
var cellEle = $(this);
// Populate select element
cellEle.html(`<select class="js-example-basic-multiple" multiple="multiple"></select>`);
// Initialise select2
let selectEle = cellEle.children("select").select2({
ajax: {
url: "/wordpressbosta/matt/wp-admin/admin-ajax.php",
dataType: 'json',
data: function (params) {
return {
q: element_id,
action: 'get_data'
};
},
type: "post",
processResults: function(data) {
var options = [];
if ( data ) {
$.each( data, function( index, text ) {
options.push( { text: text } );
});
}
return {
results: options
};
}
}
});
}
});
});
})(jQuery)
I am getting output like below.
If I click on any value, it is not set to the select box. Values are not working.
Select2 requires that each option has an id property and a text property. In the code above the processResults method is returning an array of objects which contain only a text property, without an id. When adding objects to the array in processResults an id should be included:
options.push({ id: id, text: text });
Details on this format can be found at https://select2.org/data-sources/formats. As per this page:
Blank ids or an id with a value of 0 are not permitted.
You could either use text as the id value if it's unique, or use index + 1 (+ 1 to avoid a value of 0). In the below example code text is used.
processResults: function(data) {
var options = [];
if (data) {
$.each(data, function (index, text) {
options.push({ id: text, text: text });
});
}
return {
results: options
};
}
I have this code for select2 tags method using ajax:
json data:
[
{
"id": "5",
"text": "laravel3"
},
{
"id": "4",
"text": "laravel2"
}
]
Code:
$(document).ready(function(){
$('#tag_list').select2({
placeholder: "Choose tags...",
tags: true,
minimumInputLength: 3,
tokenSeparators: [",", " "],
createSearchChoice: function(term, data) {
if ($(data).filter(function() {
return this.text.localeCompare(term) === 0;
}).length === 0) {
return {
id: term,
text: term
};
}
},
ajax: {
url: '/tags/find',
dataType: 'json',
data: function (params) {
return {
q: $.trim(params.term)
};
},
processResults: function (data) {
return {
results: data
};
},
delay: 250,
cache: true
}
});
});
With my code I can search and select data from database or add new tag to my select2 area. Now when I select data from database, <option value=""> is data id but when I add new tag <option value=""> is name(text) like this:
Now I need to change option value (get database data) from data id to data name (text). How do change option data value from id to name?!
Update: I've added more background and references to the docs, and switched the JSFiddle to using $.map() as the docs do.
The Select2 data format is described in the docs:
Select2 expects a very specific data format [...] Select2 requires that each object contain an id and a text property. [...] Select2 generates the value attribute from the id property of the data objects ...
The docs also describe how to use something other than your id:
If you use a property other than id (like pk) to uniquely identify an option, you need to map your old property to id before passing it to Select2. If you cannot do this on your server or you are in a situation where the API cannot be changed, you can do this in JavaScript before passing it to Select2
In your case, this would mean transforming the data you get back from your AJAX call, so that the id element of each result is actually the text value.
You can do that with the processResults() AJAX option. To do that using $.map as the docs do:
processResults: function (data) {
return {
// Transform data, use text as id
results: $.map(data, function (obj) {
obj.id = obj.text;
return obj;
})
};
}
Here's a working JSFiddle. Note I've set it up to simulate your real AJAX request using JSFiddle's /echo/json async option.
And here's a screenshot of the generated source, showing the value of both added tags, and those retrieved via AJAX, are the name (text):
Try this:
ajax: {
url: '/tags/find',
dataType: 'json',
data: function (params) {
return {
q: $.trim(params.term)
};
},
//updated
processResults: function (data) {
var newData = [];
$.each(data, function (index, item) {
newData.push({
id: item.id, //id part present in data
text: item.text //string to be displayed
});
});
return { results: newData };
},
//
delay: 250,
cache: true
}
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
};
}
}
}
});
I use Select2-4.0.0 I have been struggling with this problem for a whole day that to update the data.
I search every posts I can like Update select2 data without rebuilding the control, but none have them work.
What I need is really simple (a setter to data):
I have a diaglog, which had a select. Every time I open the diaglog, I will ajax for an data to keep it in a local array like:
when dialog open :
var select2List=syncToLoadTheData();//data for select2
$('#search-user-select').select2({ //here when secondly executed, the select2's data on UI does not refreshed
data:select2List,
matcher: function(params, data){
var key = params.term;
if ($.trim(key) === '') {
return data;
}
if( (matchKeyAndPinyin(key,data.text))){
return data;
}
return null;
}
}
But the problem is even though the list is changing, the select options does not change at all.Please note in my test case, every time i open the dialog, the data from server is changed:
What I had tried:
1.when init:
data: function() { return {results: select2List}; }// not work to show any data at all
2.when secondly open dialog:
$( "#search-user-select").select2('data',newdata,true);//not work to have the new data
3.when secondly open:
$("#search-user-select").select2("updateResults");//Error, does not have this method
And some other method like directly change the array's data(only one copy of the data), but none of them work.
I had the same problem before, my problem was i need to update the select2 after every ajax request with new data.
and this how i fixed my code.
EventId = $(this).attr('id');
$.ajax({
url: 'AjaxGetAllEventPerons',
type: 'POST',
dataType: 'json',
data: {id: EventId},
})
.done(function(data) {
$("#select2_job").select2({
minimumInputLength: 2,
multiple:true,
initSelection : function (element, callback) {
//var data = data;
callback(data);
},
ajax: {
url: "/AjaxGetAllPersonForEvent",
dataType: 'json',
quietMillis: 100,
data: function (term) {
return {
term: term
};
},
results: function (data) {
var myResults = [];
$.each(data, function (index, item) {
myResults.push({
'id': item.id,
'text': item.fullname
});
});
return {
results: myResults
};
}
}
});
I hope this example will help you to solve your problem
Im using jquery Select2, select2 works perfectly fine. but what i want that when page loads a default value should be loaded from controller.
Yes i already did google and yes this question have been posted many times and i cant quite get my head around it.. so thats why i need help in this.
Here is the select2 js coding:
/*----------- Select2 DropDown Common Script -------------------------*/
//For ServerSide Script
function commonSelect2(selector,url,id,text,minInputLength,placeholder){
selector.select2({
minimumInputLength:minInputLength,
placeholder:placeholder,
ajax: {
type:"post",
url: url,
dataType: 'json',
quietMillis: 100,
data: function(term, page) {
return {
term: term, //search term
page_limit: 10 // page size
};
},
initSelection : function (element, callback) {
var data = {id: element.val(), text: element.val()};
callback(data);
},
results: function(data, page) {
var newData = [];
$.each(data, function (index,value) {
newData.push({
id: value[id], //id part present in data
text: value[text] //string to be displayed
});
});
return { results: newData };
}
}
});
}
and here how i calls it from php file
{{*The Selector for Selecting the User Group*}}
var selector = $('#selectGroup');
var url = "{{base_url()}}admin/usersManageUsers/loadAllUserGroups/";
var id = "GroupID";
var text = "GroupName";
var minInputLength = 0;
var placeholder = "Select User Group";
commonSelect2(selector,url,id,text,minInputLength,placeholder);
//End of the CommonSelect2 function
I have added the initselection() function, but i don't know if i did wrote it correctly?
and in end i added this in html select2 hidden input tag.
I have tried to search on net, but looks like i am getting no where.
My Mistake.
i defined initSelection inside the ajax. Should have defined it outside ajax.
now defined initSelection() after the ajax
ajax: {
type:"post",
url: url,
dataType: 'json',
quietMillis: 100,
data: function(term, page) {
return {
term: term, //search term
page_limit: 10 // page size
};
},
results: function(data, page) {
var newData = [];
$.each(data, function (index,value) {
newData.push({
id: value[id], //id part present in data
text: value[text] //string to be displayed
});
});
return { results: newData };
}
},
initSelection : function (element, callback) {
var data = {id: element.val(), text: element.val()};
callback(data);
}