New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cache remote (ajax) requests to improve performance #110
Comments
im not sure what a good default way to cache is. every application works differently. select2 also allows paging, which in turn allows the user access to a much bigger data set and makes caching harder. if you want you can already build caching by implementing it inside the if you can think of a good default way im all ears, we can build it into the default |
I vote for having people do it in the query function, any further 'automagic' will clutter the project, and you get full flexibility. @butsjoh If you DO work out caching using the query function (which should be fairly easy) you should provide a demo function that can bee added to the docs. |
Select2 load data using ajax with caching in-place.
I hope you find it helpful. |
Any examples for how to do this in selec2 v4 in the |
Any examples for how to do this in selec2 v4 in the ajax.data callback? |
Seems like this is still in demand, so I am reopening it. |
+1 |
1 similar comment
+1 |
I forgot to share a workaround, how to cache the results with version 4.0.1 |
@M-Yankov Thanks for your example, but I found that using the query function will fire every time when user typed in regardless of the delay setting. Also select2 is going to depreciate query function per document I think transport function might be another good place to handle cache.
|
@QDCSLG Nice share ! // the type of the cacheData should be changed to object
var cacheData = this.options.get('cacheDataSource')
if (!cacheData[key]) {
cacheData[key] = listItems;
this.options.set('cacheDataSource', cacheData);
}
return cacheData[key]; The |
This is much related with each application that uses select2. Some apps are good to cache request, others not. This kind of feature makes more sense to be a responsability of developer. There are some workarounds provided by community to handle with it, if you need this in your application 👍 |
It sure would be nice if there was a flag to configure select2 to simply not destroy the ajax results once the user selects an option. Select2 is nice but I may have to stick with Selectize.js for this one select box. |
I cant find a working solution to keep the "last query" results. I agree, it would be great if the last query results could be retained even after the select list dialogue has been closed. |
@leenooks here is an adaptation of the jQuery(function($) {
//initial cache storage as array
var __cache = [];
$(selector).select2({
ajax: {
url: url, //your url
dataType: 'json',
//cache result transport
transport: function(params, success, failure) {
//retrieve the cached key or default to _ALL_
var __cachekey = params.data.q || '_ALL_';
if ('undefined' !== typeof __cache[__cachekey]) {
//display the cached results
success(__cache[__cachekey]);
return; /* noop */
}
var $request = $.ajax(params);
$request.then(function(data) {
//store data in cache
__cache[__cachekey] = data;
//display the results
success(__cache[__cachekey]);
});
$request.fail(failure);
return $request;
}
}
});
}); If you want only the "last queried" results to be cached, removing the rest, change the jQuery(function($) {
//initial cache storage as array
var __cache = [];
var __lastQuery = null;
$(selector).select2({
ajax: {
url: url, //your url
dataType: 'json',
//cache result transport
transport: function(params, success, failure) {
//retrieve the cached key or default to _ALL_
var __cachekey = params.data.q || '_ALL_';
if (__lastQuery !== __cachekey) {
//remove caches not from last query
__cache = [];
}
__lastQuery = __cachekey;
if ('undefined' !== typeof __cache[__cachekey]) {
//display the cached results
success(__cache[__cachekey]);
return; /* noop */
}
var $request = $.ajax(params);
$request.then(function(data) {
//store data in cache
__cache[__cachekey] = data;
//display the results
success(__cache[__cachekey]);
});
$request.fail(failure);
return $request;
}
}
});
}); You can also adapt these approaches to cache multiple element results or expire different caches based on a specific duration. If you want to restore the last searched value when the select option is opened, you have to handle the $(document).on('select2:closing', '.select2-hidden-accessible', function() {
var v = $('.select2-search__field').val();
$(this).data('select2LastTerm', v);
});
$(document).on('select2:open', '.select2-hidden-accessible', function(evt) {
var lastTerm = $(this).data('select2LastTerm');
window.setTimeout(function() {
//fix timing issue
if (lastTerm && lastTerm.length) {
var s = $('.select2-search__field');
s.focus();
s.val(lastTerm);
s.trigger('keyup');
s.trigger('input');
}
}, 0);
}); |
Thank you for this - I probably wasnt clear what I was hoping for. I dont necessarily want to cache queries (negating hitting the backend) - I'm hoping for the following:
Then,
IE: When you re-open the dialog (or bring the select into focus), you are currently presented with "Please enter x or more chars...", and the results of the last search are gone. Instead I would like to see the results of the last search still there so I can select from it, without having to type in a near search. (But optionally being able to perform a new search if required.) Is there a way to achieve that? |
@leenooks this thread is specifically about caching the remote response (ajax). |
Ahh, ok, I did try it, and it wasnt doing it. (And I'm using Brave as the browser.) I'll try again, thanks. |
@leenooks functional demo using standard JavaScript + jQuery https://jsfiddle.net/v10kwzL2/ |
My bad, @fyrfe - it works perfectly, thank you :) |
@leenooks updated my example to fix a timing issue on faster systems and to support browsers that do not recognize the |
Thank you very much @fyrye helped me a lot.
|
Thanks to @fyrye for his implementation. Here's mine that uses localstorage to cache results for 24 hours... // how long to cache queries in user's browser
const cacheExpire = 24; // in hours
$(selector).select2({
ajax: {
url: url,
dataType: 'json',
delay: 300,
transport: function(params, success, failure) {
// custom transport to add 24 hour caching in user's browser
const cacheKey = params.data.q || '_ALL_';
const flatVal = localStorage.getItem(cacheKey) ?? '';
const [query, strVal, dateStr] = flatVal.split('|');
if (query && strVal && dateStr) {
const date = new Date(dateStr);
const expireDate = Date.now() - cacheExpire*1000*60*60;
if (date?.getMonth && date > expireDate) {
const value = JSON.parse(strVal);
if (value) success(value); // return cached value
return;
}
localStorage.removeItem(cacheKey); // remove expired
}
const request = $.ajax(params);
request.then(function(data) {
const cacheVal = `${cacheKey}|${JSON.stringify(data)}|${(new Date()).toISOString()}`;
localStorage.setItem(cacheKey, cacheVal);
success(data);
});
request.fail(failure);
return request;
}
},
placeholder: 'placeholder',
minimumInputLength: 3
}); |
I think it would be a nice feature to implement something that the jquery tokeninput plugin is also doing. When you have configured select2 to get remote data we could cache the data coming back so if later we issue the same query again the data could be fetched from cache.
I am wondering if it would make sense to do it this way or loading all data in the beginning and configuring select2 with array data. (hence no more server loading) Any thought on this?
I can definitely help implementing this if it make sense to you.
The text was updated successfully, but these errors were encountered: