Adding a local cache to Ajax.Autocompleter

Thursday, January 26, 2006

A 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

#1
On the April 28, 2006, Daniel LaLiberte wrote:

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();
}

});

#2
On the December 14, 2006, Dummie wrote:

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

#3
On the December 29, 2006, sam wrote:

can you show example of how to use it

Thanks

#4
On the September 2, 2008, Loduis Madariaga wrote:

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);
 }
}
}()));

#5
On the September 2, 2008, Loduis Madariaga Barrios wrote:

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>

#6
On the October 24, 2008, Shyam wrote:

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.

#7
On the September 12, 2009, TDSii wrote:

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

#8
On the October 7, 2009, chris75 wrote:

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.

Random outings from a chaotic mind

The Dexagogo Rocket Australian Web Industry Association logo

Delicious

Twitter