I'm currently trying to get select2 to work, however, I'm struggling a little bit right now. What I want to achive, is fairly simple: I fetch a JSON from a webserver which consists out of key/value pairs (one ID to one string). After fetching those, I want to create options out of those and add them to select2 so they user can select one of them.
I kept as close to the code in the documentation as humanly possible:
$('#catSearchBox').select2({
width: '500px',
ajax: {
url: "url/to/data",
dataType: 'json',
delay: 250,
cache: false,
data: function (params) {
return {
searchKey: params.term
};
},
processResults: function (data, params) {
$.each(data, function(catName, catId) {
var newOption = new Option(catId, catName, false, false);
$('#catSearchBox').append(newOption).trigger('change');
});
}
},
placeholder: 'Suche nach Kategorie ...',
minimumInputLength: 3
});
Now, everything here works up until the append. When I search for anything, the options are generated correctly, however, the append seems to fail as no options are displayed at all. It looks like this:
However, it's not because of an empty or invalid response, because the options are definitely created:
I'm kinda at a loss here, I don't see why my code is not working, especially since I kept as close as possible to the code in the documentation (https://select2.org/data-sources/ajax and https://select2.org/programmatic-control/add-select-clear-items).
Does anyone have any idea on how to solve this problem? If you need any additional information I might have missed out, please let me know.
processResults Is not used to append options to the select2. It is used to transform the response from the API. It should return a valid array of objects to feed select2.
Something like:
var newData = [];
$.each(data, function(catName, catId) {
newData.push({ id: catId, text: catName });
});
return { results: newData };
I believe the main problem is in your processResults function and Select2's expectations of it.
From what I was able to partly read and partly deduce from the documentation at https://select2.org/data-sources/ajax#transforming-response-data is that processResults is supposed to return an object containing a key results and those results should be an array of objects. Further down there were some examples and one of them shows that those objects contain 2 keys - id and text.
Moreover, the info box at the top of the docs it says that select2 will create <option> only for element that was chosen (it's done for performance reasons). This implies that you are not supposed to create the <option> elements yourself, but just return the data in the expected format and select2 will take care of the rest.
This is a fiddle based on your code: https://jsfiddle.net/mkilmanas/jkx2mwv5/1/ and it doesn't work, it throws an error of trying to access results of undefined.
This is another fiddle with analogous behaviour but done according to those findings from the documentation: https://jsfiddle.net/mkilmanas/3s0kupaw/5/
I'm not sure if this is the solution but there are 2 things in your code that I don't like so much.
Try this:
processResults: function (data, params) {
// First, remove all previous elements
$('#catSearchBox').html('');
$.each(data, function(catName, catId) {
var newOption = new Option(catId, catName, false, false);
$('#catSearchBox').append(newOption);
});
// Second, fire change when all elements are appended
$('#catSearchBox').trigger('change');
}
Related
I'm using django-autocomplete-light and want to add action buttons do update/delete choices. So, I don't understand clearly how I can update/delete value and trigger change specific field.
Is there a clear documentation about that somewhere ?
My answer is based on the following link: https://github.com/yourlabs/django-autocomplete-light/issues/1092
(change) This work for me:
$.ajax({
type: 'GET',
url: `your-url`
}).then(function (response) {
response.results.forEach((element, _, __) => {
var option = new Option(element.text, element.id, true, true);
field.append(option);
});
field.trigger('change');
});
My GET RESPONSE is:
response = {
results: [
{id: 1, text: "label"}
]
}
I don't think this solution is complete, but this is what I've been doing for programmatically selecting an option for Select2QuerySetViews:
$('#select2-<field_id>-container').val(<object_key>).html(<object_str>).trigger('change')
So to get this to work you need:
field_id: ID of the input element
object_key: primary key of the selected model
object_str: string representation of the model (whatever is returned by __str__).
I know this doesn't fully answer your question, but I'm hoping there's some value. There wasn't much documentation on how to do this either. Would love if someone could improve on this.
I'm working on creating an interface for some system I am working on and I am required to write the Javascript around pre-existing PHP AJAX functions that are used elsewhere in the system (purely as the person who does our DB stuff is too busy to adapt the code to my needs).
Using Select2 I need to make a select field where the user searches for their name in the database and selects the one matching it so it can then be posted to another AJAX function later. I have done this with the following code:
//<select id="sltMyName" style="width: 100%;"></select>
$("#sltMyName").select2({
ajax: {
type: "POST",
url: "includes/php/report_searchPlayers.php",
delay: 250,
data: function (params) {
return {
q: params.term // search term
};
},
processResults: function (data) {
console.log({ results: data.split(",") });
return { results: data.split(",") };
}
},
minimumInputLength: 1
});
This should turn a returned string in the format of name1,name2,name3,name... into the required format for Select2 to display, however, it does not currently work. The dropdown just appears blank.
I've seen some questions referring to a text and id attribute, however, they are all in the context of a JSON string being returned, so I am not sure if they are required here and how to utilise them in this context. Furthermore, I cannot find any of this in the documentation.
Any suggestions? Thanks in advance.
Data returned:
Tommy,Jak_Tommy_Lee_Jones,Tommy_Shelby,Tommy_Balboner,TommyCZ,GA_Tommy,VA_Tommy,Tommy_Skrattar,Tommy_Knocker,Tommy_of_Elektro,Tommy_the_Destroyer,Old_Tommy,tommy_of_house_shelby,TommyDermo,TommyC,TommyCash_CZ,Tommyb69k,SA_Tommy,tommyfaster,Tommy_See,Tommy_de_Destroyer,Tommy_of_Whiteroses,TommyShelby,Templar_Intiate_Tommy,Templar_Initiate_Tommy,tommysuckspp,Tommy_the_Overweight
I think I've figured it out. The main issue is that the data that Select2 wants to use needs to be an array of objects with at least a property named id and a property named text. In the processResults function, just create those objects & then the dropdown will populate with the data from your URL!
I've noticed that it tries to filter the data as i type, but since the url I passed in does not accept the parameters, it just returns the same data each time. Let me know if you need a more robust example.
See my fiddle at https://jsfiddle.net/yp0rp2kw/3/ for a working solution.
I want to add ordering to the search query for the Youtube JS API but I cannot get it to work.
This is a standard search using browser
https://www.youtube.com/results?search_query=test
This is part of the script that does the same search but using the player
player.cuePlaylist({listType:'search', list:'test'});
Tested it and it works perfectly. However when I want to add ordering to the search query. It doesn't work.
For example, the searching for test with extra filter "Today". IT doesn't work (play list is empty array).
The browser search is
https://www.youtube.com/results?sp=CAESAggC&q=test
This however
player.cuePlaylist({listType:'search', list:'sp=CAESAggC&q=test'});
Does not yield a result. The documentation states:
If the listType property value is search, then the list property specifies the search query.
I tried replacing & with & a m p ;(without spaces) but still no dice.
I also couldn't find anything related to filtering in the documentation.
Basically the question is how do I apply filtering to the cuePlaylist method.
Edit:
Tried this:
player.cuePlaylist({listType:'search', list:'test', sp:'CAESAggC'});
The sp didn't do anything
I'm not sure if cuePlaylist supports filtering but, the closest I can suggest is to use a search function
type: 'GET',
data: {
key: 'API_KEY',
q: query,
part: 'snippet'
}
})
then add a order by or any filters you can add, you can check Search document for additional info.
Here is a snippet for it :
// search video
$("#search").click(function() {
var query = $("#query").attr("value");
if ( !query ) {
return;
}
$.ajax({
url: 'https://www.googleapis.com/youtube/v3/search',
dataType: 'json',
type: 'GET',
data: {
key: 'AIzaSyBda8mhaE8x10RiF0uzvBMPUszbUIQsy0g',
q: query,
part: 'snippet'
}
}).done(function(data) {
player.stopVideo();
player.clearVideo();
$('#video').fadeIn();
var videos = [];
console.log(data);
$.each(data.items, function() {
console.log(this.id.videoId)
videos.push(this.id.videoId);
});
// sort by favorite
videos = videos.sort(function(a, b) {
return b.favoriteCount - a.favoriteCount;
});
player.cuePlaylist(videos);
});
});
});
Here is the source for the snippet, I made some adjustment using the tutorial because the github is using api v2.
Hope this helps!
By default, the typeahead plugin makes use of a single data source in order to fetch the results. What I would like is for it to search within multiple fields, so if say, I have:
var items = [
{'title': 'Acceptable', 'description': 'Good, but not great'}
]
It will search on both the title and description fields, ideally via AJAX.
Is this possible with this plugin?
Typeahead does not support using JSON objects without two tweaks. There are few pull-requests in Github for this, and I have submitted one myself, but, currently, you must manually override select and render. Additionally, you must also override highlighter, matcher, sorter, and updater, but those can done via the options passed into the typeahead.
var typeahead = control.typeahead({ /* ... */ }).data('typeahead');
// manually override select and render
// (change attr('data-value' ...) to data('value' ...))
// otherwise both functions are exact copies
typeahead.select = function() {
var val = this.$menu.find('.active').data('value')
this.$element.val(this.updater(val)).change()
return this.hide()
};
typeahead.render = function(items) {
var that = this
items = $(items).map(function (i, item) {
i = $(that.options.item).data('value', item)
i.find('a').html(that.highlighter(item))
return i[0]
});
items.first().addClass('active')
this.$menu.html(items)
return this
};
If you need help with the other ones, then let me know, but the gist of it is:
control.typehead({
matcher: function (item) {
var lcQuery = this.query.toLowerCase();
return ~item.title.toLowerCase().indexOf(lcQuery)
|| ~item.description.toLowerCase().indexOf(lcQuery);
}
};
I also have a JFiddle example related to the pull request that I made, but the sorting functions do not exist in 2.3.1, or even 3.x without the pull request being accepted, so you will have to override sorter in its entirety to effectively repeat what I did with matcher above (checking both while sorting).
As for the AJAX call, you can override the source method in the passed in options to get AJAX functionality. By not returning to the source call, it assumes that the second parameter, process, will be invoked with results.
control.typehead({
minLength: 3,
source: function(query, process) {
$.ajax({
url: url + encodeURIComponent(query),
type: 'GET',
success: process,
error: function() { /* ... */ }
});
}
});
Typeahead added support for multiple field searching in v10.3
https://github.com/twitter/typeahead.js/pull/811
Usage:
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('title', 'description'),
I found many discussions that were close to what I need, and this question is the
closest - How can I set postData._search to true in the request in jqGrid?.
As I'm struggling with almost the same problem, and just can't get it working - I want to setup "search" and "filters" during the initial loading of the jqGrid - say, on the page reload, and I have my filters stored in the session - and I tried everything I found in Oleg's examples - it just doesn't work!
That's what I'm trying to do -
loadBeforeSend: function (xhr) {
var grid = jQuery('#' + block_id);
var postData = grid.jqGrid('getGridParam','postData');
jQuery.extend(postData,{filters:MyFilters});
grid.jqGrid('setGridParam', {search: true, postData: postData});
console.log(grid.jqGrid('getGridParam','postData'));
}
The console printout shows that the filters are in place, but the _search is still false, and the actual Post gets sent even with no filters:
_search false
block_id report_block_1table
nd 1297451574526
page 1
rows 25
sidx id
sord desc
However, if I put exactly the same code - with the addition of
grid.trigger("reloadGrid");
line - into some button's onClickButton function, and later click the button - everything works; but I need to make it work on "page reload"!
Any ideas? It's driving me crazy...
It seems to me that you are not the first person who ask the same question. Recently I asked on the close question (read many comments to the answer). Another old answer including the demo could probably answer on some your opened questions.
Your code using beforeRequest don't work just because the function beforeRequest will be caled immediately before the ajax call and the changing of the search parameter is too late. Moreover overwiting of filters everytime is probably not the best idea. In the case the user will not able to set any other grid filter.
So I can repeat, that the imlementation of the solution which you need is very simple. You should just set filters property of the postData parameter of jqGrid to the filter which you need and set another jqGrid parameter search:true additionally. It's all! Later the user will be able to open advance searching dialog and overwrite the filters. The user can also click on "Reset" button of the advance searching dialog and set filters to empty string and search:false.
For better understanding I have to clear how search parameter or some other jqGrid will be used in the URL. There are parameter prmNames of jqGrid which defines the names of parameters send as a part of URL or as a part of data POSTed to the server. The default value of prmNames contain search:"_search" and the code of internal populate function used by jqGrid has the following simplified code fragment:
var prm = {}, pN=ts.p.prmNames;
if(pN.search !== null) {prm[pN.search] = ts.p.search;}
if(pN.nd !== null) {prm[pN.nd] = new Date().getTime();}
if(pN.rows !== null) {prm[pN.rows]= ts.p.rowNum;}
if(pN.page !== null) {prm[pN.page]= ts.p.page;}
if(pN.sort !== null) {prm[pN.sort]= ts.p.sortname;}
if(pN.order !== null) {prm[pN.order]= ts.p.sortorder;}
...
$.extend(ts.p.postData,prm);
where
prmNames: {page:"page",rows:"rows", sort: "sidx",order: "sord", search:"_search",
nd:"nd", id:"id",oper:"oper",editoper:"edit",addoper:"add",
deloper:"del", subgridid:"id", npage: null, totalrows:"totalrows"}
So to set _search parameter of URL one should set search parameter of jqGrid.
Look at the following demo. You can easy to verify using Fiddler of Firebug that the jqGrid from the page send HTTP GET with the following url:
http://www.ok-soft-gmbh.com/jqGrid/MultisearchFilterAtStart1.json?filters=%7B%22groupOp%22%3A%22AND%22%2C%22rules%22%3A%5B%7B%22field%22%3A%22invdate%22%2C%22op%22%3A%22gt%22%2C%22data%22%3A%222007-09-06%22%7D%2C%7B%22field%22%3A%22invdate%22%2C%22op%22%3A%22lt%22%2C%22data%22%3A%222007-10-04%22%7D%2C%7B%22field%22%3A%22name%22%2C%22op%22%3A%22bw%22%2C%22data%22%3A%22test%22%7D%5D%7D&_search=true&nd=1297508504770&rows=10&page=1&sidx=id&sord=asc
So it do exactly what you need. The code of the demo contain the following code fragment:
$("#list").jqGrid({
url: 'MultisearchFilterAtStart1.json',
datatype: "json",
postData: {
filters:'{"groupOp":"AND","rules":['+
'{"field":"invdate","op":"gt","data":"2007-09-06"}'+
',{"field":"invdate","op":"lt","data":"2007-10-04"}'+
',{"field":"name","op":"bw","data":"test"}]}'
},
search:true,
// ...
});
#Oleg Oleg's answer works like a charm but just for the first time.
For me when I reload the grid, filters and search flag are not set up.
With the following code each time I reload the grid it also sends the filters and search flag.
I use server side sort and pagination.
I'm using:
jQuery("#myGrid").navGrid("#myPager", {search: true, refresh: true, edit: false,
add:false, del:false}, {}, {}, {}, {});
On the grid definition:
beforeRequest: function() {
// filter to be added on each request
var filterObj1 = {"field":"myField","op":"eq","data":"myValue"};
var grid = jQuery("#myGrid");
var postdata = grid.jqGrid('getGridParam', 'postData');
if(postdata != undefined && postdata.filters != undefined ) {
postdata.filters = jQuery.jgrid.parse(postdata.filters);
//Remove if current field exists
postdata.filters.rules = jQuery.grep(postdata.filters.rules, function(value) {
if(value.field != 'myField')
return value;
});
// Add new filters
postdata.filters.rules.push(filterObj1);
} else {
jQuery.extend(postdata, {
filters: {
"groupOp":"AND",
"rules":[filterObj1]
}
});
// more filters in the way: postdata.filters.rules.push(filterObj1);
}
postdata.filters = JSON.stringify(postdata.filters);
postdata._search = true;
return [true,''];
}