Welcome to Xierpa. This is the stable 1.2 version which was developed by Petr van Blokland + Claudia Mens (buro@petr.com) and is maintained by Michiel Kauw-A-Tjoe. It is subclassed by the Museum Meermanno and American Express applications.

Ajax

What is it?

Ajax, or AJAX, is a web development technique used for creating interactive web applications. The intent is to make web pages feel more responsive by exchanging small amounts of data with the server behind the scenes, so that the entire web page does not have to be reloaded each time the user requests a change. This is intended to increase the web page's interactivity, speed, functionality, and usability.

The name is shorthand for Asynchronous JavaScript and XML. Ajax is asynchronous in that loading does not interfere with normal page loading. JavaScript is the programming language in which Ajax function calls are made. Data retrieved using the technique is commonly formatted using XML, as reflected in the naming of the XMLHttpRequest object from which Ajax is derived.

Ajax is a cross-platform technique usable on many different operating systems, computer architectures, and Web browsers as it is based on open standards such as JavaScript and XML, together with open source implementations of other required technologies.
(See also Wikipedia)

How is Ajax implemented in Xierpa?

Xierpa uses Mochikit for generating the Javascript: http://mochikit.com
There are five components that play a rol in an Ajax function:

  • The calling form such as entry or popup that generates the event to call the Javascript function;
  • The Javascript function that sends the server request using Mochikit loadJSONDoc();
  • The application on the server side that translates the url request into a JSON result;
  • The Javascript function that gets called when the result reaches the browser;
  • The target HTML tag that gets the updated content (e.g. an popup or div.

How to use Ajax in Xierpa?

@@@ Add here SiteBuilder even subscriptions.
An Ajax implementation needs code on two sides:
I made several attempts to write an “AjaxBuilder” class in order to write the required Javascript from a Python class. But as it turns out that is not really worth the effort. Either the lumps of code get too specialized, in which case I have to write a lot of similar method (in fact one for each application) or the indirect programming leads to very complex structures that are more complex than writing the Javascript directly. So I decided to write a set of very generic templates with guidelines that can be used by copy/paste.
Below you’ll find an example of popup-filling by Ajax request. See the other examples for details description of these templates.
The source code on this page has the function of example only. For constitent template code, click on the links below to the various example ajax applications:

To solve all of the above eventually a different route was taken, to make the use of Ajax fast and standard, while keeping all the flexibility of the Xierpa (form) coding. All required methods for this approach are implemented in SiteBuilder (allowing not only CMS application to use Ajax, but all regular sites as well).

Ajax high level

All high level Ajax functions are included in the SiteBuilder class. @@@ Examples here.

Ajax low level

Page side

Inside the head the following source must be included to include the Mochikit library and to load the specific Javascript of the ajaxpopup function.
self.head()
...
self.script(src="/_root/_xsl2/js/MochiKit/MochiKit.js")	
self.script(src='./_js/ajaxpopup.js')
...
self._head()
To make sure that log() output is not printed in the standard browser error/Javascript window (if you don’t want that), add the following to the head tag
self.head()
...
self.script()
MochiKit.Logging.logger.useNativeConsole = false;
self._script()
...
self._head()
To open a the standard Mochikit debug window choose this url in the browser: javascript:MochiKit.Logging.logger.debuggingBookmarklet()

The file named "./_js/popup.js" contains the following Javascript
// -------------------------------------------------
// Implementing "AjaxPopup" fill from Ajax request
//
AjaxPopup = function(){
	bindMethods(this);
	//log("Hello, this is the AjaxPopup controller.");
}
AjaxPopup.prototype.do = function(url, targetid, sourceid){
	log("do get value from source", sourceid);
	// Assume that the source element has an attribute named "value"
	// Get the value from the calling element
	var select = getElement(sourceid).value; 
	
	// Construct the url for the Ajax server page
	// Here we have 2 parameters: targetid and value
	// We may assume that the mode parameter is already part of the url.
	url = url + '/-/targetid-' + targetid + '/value-' + select;
	log("do attempt on url", url);
	
	// Fire the request and implement the Callback and Errback functions.
	var d = loadJSONDoc(url);
	d.addCallback(this.load);
	d.addErrback(this.loadError);
}
AjaxPopup.prototype.loadError = function(results){
	log("loadError", results);
}
AjaxPopup.prototype.load = function(results){
	log("load start");

	// "results" contains "mode" (string),
	// "targetid" (string) and "content" (record list)
	// Get the result from the Ajax request
	var mode = results.mode;
	var targetid = results.targetid;
	var content = results.content;
	log("load", targetid, content);
	
	// Clear the target popup
	replaceChildNodes(targetid);
	
	// For all the records we got in the result, 
	// add an OPTION element to the popup.
	for (i in content){
		record = content[i];
		// record is a dictionary with keys id and value
		log("Adding option", record.id, record.value);
		appendChildNodes(targetid, OPTION({'value': record.id}, record.value));
	};
}
// Create an instance of this Javascript "class"
ajaxpopup = new AjaxPopup();

An example of the calling page code could be
	targetid = 'mytarget'	# Id of the target popup
	sourceid = 'mysource'	# Id where to get the source value from
	path = e.path2basedpath('.	/getajax/-/mode-popupdemo')
	self.text('Type a value between 1 and 100 to change the option list in the popup')
	self.br()
	# This is the sending form element with id "sourceid"
	self.entry(type="text", id=sourceid, width=4, 
		onkeyup="ajaxpopup.do('%s', '%s', '%s');return false;" % 
			(path, targetid, sourceid))
	self.br()
	# This is the receiving form element with id "targetid"
	# Add attribute default=None to remove the top 
	# default option from the popup
	self.popup(id=targetid, path='mypath', options=[], default=None)

Server side

A typical server page could be defined as follows

# -*- coding: UTF-8 -*-
# -----------------------------------------------------------------------------
#	xierpa server
#	(c) 2007 buro@petr.com, www.petr.com
#	
#	X I E R P A
#
#	No distribution without permission.
#
# -----------------------------------------------------------------------------
#
#	getajax.py
#
from xpyth.xierpa.builders.xierpabuilder import XierpaBuilder

class GetAjax(XierpaBuilder):
	#
	#	This is a demo server for Ajax requests.
	#	Normally this will operate with and agent/database connection, but for
	#	this demo situation we operate with a fixed algoritm.
	#	
	#	Copy the mode and targetid to the back into the output
	#	Take the value and select a list of values for the popup
	#
	def build(self):		
		
		mode = e.form['mode']

		d = {}
		# Always give the targetid back to the page.
		d['targetid'] = e.form['targetid']	
		d['content'] = []
		# Return the mode
		d['mode'] = mode
			
		
		if mode == 'popupdemo':	# Additional safety and data selector	
			# Answer JSON with a list of names from the request organization
			# /xierpa/xierpa/pattern/examples/getajax/-/mode-popupdemo/targetid-mysource/value-123
			try:
				value = max(0, min(100, int(e.form['value'])))
				for n in range(0,value):
					record = {}
					record['id'] = n + 1
					record['value'] = 'This is choice #%02d out of %d' % (n + 1, value)
					d['content'].append(record)
			except ValueError:
				record = {}
				record['id'] = 1
				record['value'] = 'Type only numbers'
				d['content'].append(record)
		
		elif myoption == 'typeaheaddemo':
			pass
		
		self.text(self.buildJSON(d))
		
GetAjax(e, result).build()

This “page” returns a JSON script. The syntax of a JSON is easy to read by the Mochikit Javascript code on the page side. It looks a bit like Python dict/list source code.

Do’s and don’ts

Writing Javascript in general, and Ajax specific, has the problem that it is hard to debug. Especially the two-sided connection between sending/receiving on the client side and the server side is difficult to trace if there are any errors. Below is a list of do’s and don’ts that may help finding errors.
  • Try to test the server side with a set of manual created url’s and check if the resulting JSON source is right;
  • Make sure that all parameters are in the requesting url (such as function, targetid and value);
  • Use a debug window in the browser to see what happens with the Javascript;
  • Use Mochikit’s log() to see where the Javascript goes;