AJAX Caching with Titanium Appcelerator

So I’ve had quite a few questions about how I do AJAX caching in Titanium Appcelerator. So, here’s my solution.

First, I needed some persistent storage with a very general structure. I could have gone with flat files, but I decided to make use of the built-in SQLite engine, so that I could easily access entries and delete old data.

Database

<br />
var db_conn = Ti.Database.open('app_db1');<br />
db_conn.execute('CREATE TABLE IF NOT EXISTS <code>remote_cache</code><br />
                 (key TEXT, type TEXT, valid_till TEXT, value TEXT,<br />
                 PRIMARY KEY (key, type))');<br />

Next, I need a wrapper class for my ajax calls. Note the “get” function which is the main function call. Here is the signature and explaination:

get: function (url, params, type, valid_for, callback, skip_cache)

  • url : string : the full url to call
  • params : object : a simple object with name/value parse for POST variables
  • type : string : the cache domain for this call. Usefull for clearing all cache data for a specific domain
  • valid_for : date string : the amount of time the cache should remain valid for
  • callback : function : the function to call on completion or fail of the request
  • skip_cache : boolean : an option to bypass the cache and perform write through

AJAX Class

</p>
<p>var ajax =<br />
{<br />
	http_conn: Ti.Network.createHTTPClient(),<br />
	url:'',<br />
	type:'',<br />
	params:{},<br />
	key:'',<br />
	valid_for: '+1 hour',<br />
	callback: null,<br />
	debug:true,<br />
	get: function (url, params, type, valid_for, callback, skip_cache)<br />
	{<br />
		this.key = MD5(url + '|' +   JSON.stringify(params));<br />
		this.url = url;<br />
		this.params = params;<br />
		this.valid_for = valid_for;<br />
		this.type = type;</p>
<p>		this.callback = callback;</p>
<p>		if (ajax.debug) Titanium.API.info('Ajax Call');<br />
		if (skip_cache)<br />
		{<br />
			this.remote_grab();<br />
		}<br />
		else if (!this.local_grab())<br />
		{<br />
			this.remote_grab();<br />
		}</p>
<p>	},<br />
	abort : function ()<br />
	{<br />
		this.http_conn.abort();<br />
	},</p>
<p>	local_grab: function ()<br />
	{<br />
		if (ajax.debug) Titanium.API.info('Checking Local key:' + this.key);</p>
<p>		var rows = db_conn.execute('SELECT valid_till, value FROM remote_cache WHERE key = ? AND type = ? AND valid_till &gt; datetime(\'now\')',  this.key, this.type);//, '', '+this.valid_for+')');//',  this.key, 'date(\'now\', '+this.valid_for+')');<br />
		var result = false;<br />
		if (rows.isValidRow())<br />
		{<br />
			if (ajax.debug) Titanium.API.info('Local cache found with expiration:' + rows.fieldByName('valid_till'));<br />
			var result = JSON.parse(rows.fieldByName('value'));<br />
			rows.close();</p>
<p>			this.callback(result);<br />
			result = true;<br />
		}<br />
		rows.close();<br />
		return result;<br />
	},</p>
<p>	remote_grab: function ()<br />
	{<br />
		if (ajax.debug) Titanium.API.info('Calling Remote: ' + this.url + ' - PARAMS: '+ JSON.stringify(this.params));</p>
<p>		this.abort();<br />
		this.http_conn.setTimeout(10000);</p>
<p>		// catch errors<br />
		this.http_conn.onerror = function(e)<br />
		{<br />
			//alert('Call failed');<br />
			ajax.callback({result:false});<br />
			Ti.API.info(e);<br />
		};</p>
<p>		// open connection<br />
		this.http_conn.open('POST', this.url);</p>
<p>		// act on response<br />
		var key = this.key;<br />
		var valid_for = this.valid_for;<br />
		var callback = this.callback;<br />
		var type = this.type;</p>
<p>		this.http_conn.onload = function()<br />
		{<br />
			if (ajax.debug) Titanium.API.info('Response from server:' + this.responseText);<br />
			if (this.responseText != 'null')<br />
			{<br />
				var response = JSON.parse(this.responseText);<br />
				if (response.result == true || (response &amp;&amp; response.length &gt; 0))<br />
				{<br />
					ajax.update_local(key, type, valid_for, response);<br />
					callback(response);<br />
				}<br />
				else if (response.result == false &amp;&amp; response.error  &amp;&amp; response.error.length &gt; 0)<br />
				{<br />
					callback({result:false,error:response.error});<br />
				}<br />
				else<br />
				{<br />
					callback({result:false,error:'Invalid Result (1)'});<br />
				}<br />
			}<br />
			else<br />
			{<br />
				callback({result:false,error:'Invalid Result (2)'});<br />
			}<br />
		};</p>
<p>		// Send the HTTP request<br />
		this.http_conn.send(this.params);</p>
<p>	},</p>
<p>	update_local: function (key, type, valid_for, response)<br />
	{<br />
		if (ajax.debug) Ti.API.info('Updating Cache: KEY: ' + key + ' TYPE: ' + type +' - FOR: '+valid_for+', ' + JSON.stringify(response));<br />
		db_conn.execute('DELETE FROM remote_cache WHERE (valid_till &lt;= datetime(\'now\') OR key = ?) AND type = ?', key, type);<br />
		db_conn.execute('INSERT INTO remote_cache ( key, type, valid_till, value ) VALUES(?,?,datetime(\'now\',?),?)',key, type, valid_for, JSON.stringify(response));<br />
	}<br />
};<br />

One thought on “AJAX Caching with Titanium Appcelerator

  1. magico says:

    Great share thank you!!
    you library is great!!

    just one question from a newbie:

    I’m including the lib with:


    var ajax = require("ajax") //coped ajax.js into /lib
    //then i have to use like:
    ajax.ajax.get(...)

    //is it possible to export directly so i can just call it like:
    ajax.call(...) ??

    I tried with:

    var ajax = require(“ajax”).ajax

    //changed the exports into
    exports.ajax = { your code}

    //but nothing!
    thank you!!

Leave a Reply

Your email address will not be published. Required fields are marked *