Adding a local cache to Ajax.Autocompleter
Thursday, January 26, 2006A very small but perhaps useful enhacement to the Ajax.Autocompleter class. I've called it Ajax.CachedAutocompleter so as not to interfere. It's an exact copy of Ajax.Autocompleter, with a few extra lines.
Instead of performing an XmlHttpRequest for every token (the word the user is typing in), it'll first check the local cache (a simple associative array) and if an entry with the token as key is present it'll use that text instead. Any token that is not cached will be, by saving the request.responseText into the array with the token as the key.
Basically it speeds up user corrections to the token; if they type in a word then delete some letters, the autocompleter might be able to pull it from the cache instead of via XmlHttpRequest. I thought someone might find it useful.
Ajax.CachedAutocompleter = Class.create();
Object.extend(Object.extend(Ajax.CachedAutocompleter.prototype, Autocompleter.Base.prototype), {
initialize: function(element, update, url, options) {
this.baseInitialize(element, update, options);
this.options.asynchronous = true;
this.options.onComplete = this.onComplete.bind(this);
this.options.defaultParams = this.options.parameters || null;
this.url = url;
this.cache = {};
},
getUpdatedChoices: function() {
var t = this.getToken();
if(this.cache[t]) {
this.updateChoices(this.cache[t]);
} else {
entry = encodeURIComponent(this.options.paramName) + '=' +
encodeURIComponent(t);
this.options.parameters = this.options.callback ?
this.options.callback(this.element, entry) : entry;
if(this.options.defaultParams)
this.options.parameters += '&' + this.options.defaultParams;
new Ajax.Request(this.url, this.options);
}
},
onComplete: function(request) {
this.updateChoices(this.cache[this.getToken()] = request.responseText);
}
}); In practice I find it does improve performance noticably in situations where the token is being corrected.
8 Comments
Very useful. Thanks.
I've written a merge of Ajax.Autocompleter and Autocompleter.Local in which an array of items is returned by the Ajax request, instead of a string. This allows cleaner local manipulation of the array, such as to support name-value pairs, hierarcies, etc, and it would work well with your cache too.
// Variation on Ajax.Autocompleter and Autocompleter.Local.
// Uses modified version of http://wiki.script.aculo.us/scriptaculous/show/ExtendClassFurther
Autocompleter.LocalAjax = Autocompleter.Local.extend(
{
initialize: function(element, update, url, options)
{
this.baseInitialize(element, update, options);
this.options.asynchronous = true;
this.options.onComplete = this.onComplete.bind(this);
this.options.defaultParams = this.options.parameters || null;
this.url = url;
},
getUpdatedChoices: function()
{
entry = encodeURIComponent(this.options.paramName) + '=' +
encodeURIComponent(this.getToken());
this.options.parameters = this.options.callback ?
this.options.callback(this.element, entry) : entry;
//alert('defaultParams: ' + this.options.defaultParams);
if (this.options.defaultParams)
this.options.parameters += '&' + this.options.defaultParams;
// Get the super method now to be called when AJAX response is handled.
this.superGetUpdatedChoices = Class.get_super_method(this.__class__, "getUpdatedChoices");
new Ajax.Request(this.url, this.options);
},
onComplete: function(request) {
//alert('got responseText: ' + request.responseText);
var rawItems = eval(request.responseText);
var items = []
rawItems.each(function(item)
{ if (item) items.push({value: item.name, label: item.value}) });
//alert('options: ' + options);
this.options.array = items;
this.superGetUpdatedChoices();
}
});
It is nice, thanks a lot :)
What do you think, can I preload the list for autocompletion? Becasue this autocompletion with 10.000 elements is relly slowly... :/
And in IE 7 more slower...
bye
can you show example of how to use it
Thanks
I want felicitarte for the work they realizates, here sending some improvements and adjustments
Ajax.CachedAutocompleter = Class.create();
Object.extend(Object.extend(Ajax.CachedAutocompleter.prototype, Autocompleter.Base.prototype), (function (){
var auto_complete_cache = {};
return {
initialize: function(element, update, url, options) {
this.baseInitialize(element, update, options);
this.options.asynchronous = true;
this.options.onComplete = this.onComplete.bind(this);
this.options.defaultParams = this.options.parameters || null;
this.url = url;
this.options.workSpace = this.options.workSpace || (this.element.id || this.element.name);
if (auto_complete_cache[this.options.workSpace] === undefined) {
auto_complete_cache[this.options.workSpace] = {};
}
},
getUpdatedChoices: function() {
var t = this.getToken();
if(auto_complete_cache[this.options.workSpace][t]) {
this.updateChoices(auto_complete_cache[this.options.workSpace][t]);
} else {
entry = encodeURIComponent(this.options.paramName) + '=' +
encodeURIComponent(t);
this.options.parameters = this.options.callback ?
this.options.callback(this.element, entry) : entry;
if(this.options.defaultParams)
this.options.parameters += '&' + (typeof this.options.defaultParams == 'string' ? this.options.defaultParams : Object.toQueryString(this.options.defaultParams));
new Ajax.Request(this.url, this.options);
}
},
onComplete: function(request) {
this.updateChoices(auto_complete_cache[this.options.workSpace][this.getToken()] = request.responseText);
}
}
}()));
Restriction of the elements load
<pre>
Ajax.CachedAutocompleter = Class.create();
Object.extend(Object.extend(Ajax.CachedAutocompleter.prototype, Autocompleter.Base.prototype), (function (){
var auto_complete_cache = {};
return {
initialize: function(element, update, url, options) {
this.baseInitialize(element, update, options);
this.options.asynchronous = true;
this.options.onComplete = this.onComplete.bind(this);
this.options.defaultParams = this.options.parameters || null;
this.url = url;
this.options.workSpace = this.options.workSpace || (this.element.id || this.element.name);
if (auto_complete_cache[this.options.workSpace] === undefined) {
auto_complete_cache[this.options.workSpace] = {};
} else if (Object.values(auto_complete_cache[this.options.workSpace]).length >= 5000) {
auto_complete_cache[this.options.workSpace] = {};
}
},
getUpdatedChoices: function() {
var t = this.getToken();
if(auto_complete_cache[this.options.workSpace][t]) {
this.updateChoices(auto_complete_cache[this.options.workSpace][t]);
} else {
entry = encodeURIComponent(this.options.paramName) + '=' +
encodeURIComponent(t);
this.options.parameters = this.options.callback ?
this.options.callback(this.element, entry) : entry;
if(this.options.defaultParams)
this.options.parameters += '&' + (typeof this.options.defaultParams == 'string' ? this.options.defaultParams : Object.toQueryString(this.options.defaultParams));
new Ajax.Request(this.url, this.options);
}
},
onComplete: function(request) {
this.updateChoices(auto_complete_cache[this.options.workSpace][this.getToken()] = request.responseText);
}
}
}()));
</pre>
Hi,
I need to trigger the autocomplete event while clicking on a button. My aim is to display all on button click. I am using AjaxTags library. As you have a good knowledge about this library, I know you can help me. Please help me.
all i can see here is codes and more improved codes, without the real class or how to implement.
pretty useless, i would like anyone to point me to any address that can help, please send me an email will be much appreciated.
demonminds [at] gmail [dot] com
Great stuff, thanks !
In latest version of Scriptaculous, Ajax.Autocompleter.getUpdatedChoices() starts by calling this.startIndicator();
I think that your cached version should do the same.
Cheers.