SimpleAsynch

It's been almost a month since I last made a post. Sorry but I've been busy, mainly with work. I can only spend a few hours a week working on this. I'll make up for it with two posts in one day. The first post is to talk a little more about the asynchronous library I originally created for this blog. It's called SimpleAsynch. I't's been enhanced a bit and I'm now using it on a new application that I'll talk about a later. (Sorry Patrick, I haven't been writing games where things blow up. I promise to do that next.)




The world doesn't really need another asynchronous library, but this one is different. I created it. That doesn't make it better just different. Something else that might make this different is how the requests and responses are constructed and used.

1.Construct a request and submit it to the application server through a post action using XMLHttpRequest.
2.On the application server treat the request as any standard post request, parse the parameter list and perform an action, database update, reach out to a web service, etc.
3.When we're ready to return a response, use the asynchronous library to construct a XML document. In the document is a list of action node. Each action node is made up of an action (duh), the action recipient which could be an element id or JavaScript function, and finally a value to either store in the element or pass to a callback.
4.The response is then returned to the browser where the asynchronous library loops through and executes all of the actions.




There are several actions available:

input - populate an input field, if it doesn't exist create a hidden input field and store the value
div - replace the innerHTML of the div with the value supplied
options - replace all options in a select with the comma delimented option list stored in the value
select - set the selected option in a select to the value supplied
tab - if we use the tabber.js library, we can use this action to activate the tab named in the value parameter
delayCallback - we can use this to execute a callback function on the client, I can't remember why I needed this, I had a reason
callback - use the callback to execute yes a callback, the callback function could build another asynchronous request, we actually do this on the admin piece for the blog and on the project application that I'll talk about later
alert - the alert action will display an alert with the name and value concatenated, useful for reporting errors or for debugging

Now the first version of SimpleAsynch did not construct a XML response, but returned a pipe delimented set of actions, ids, and values. While the delimented response was initially easier to construct and prove out, it was a pain to manage and debug once more complex actions were performed. The project application uses the XML version, while the blog and Salesforce applications use the old delimited version.

The current library accommodates the most important of all browsers, IE6. There are no other browsers. That's wrong. It actually supports all browsers that I have access to IE6, IE7, Firefox 3 on Windows and Linux, Safari 3 on Mac and iPod. I've not downloaded Safari 4 yet nor I have I tried it on Chrome.

Now for some sample code...
The event handler on the browser constructs the request using SimpleAsynch.


function updateProject(){
var request = ""
request = addRequestFunction(request,"updateProject",false);
request = addRequestParameter(request,"projectId",false);
request = addRequestParameter(request,"projectName",false)
request = addRequestParameter(request,"projectStatus",false)
request = addRequestParameter(request,"projectDescription",false)
request = addRequestParameter(request,"projectScheduledStart",false)
request = addRequestParameter(request,"projectScheduledStop",false)
request = addRequestParameter(request,"projectActualStart",false)
request = addRequestParameter(request,"projectActualStop",false)
request = addRequestParameterAndValue(request,"projectAccessList",getAccessList(),false)
request = addCallback(request,"clearProjectForm",true);
postRequest("/updateProject",request);
}

There are a few functions that can be used to add parameters, addRequestFunction, addRequestParameter, addRequestParameterAndValue, and addCallback. The addRequestParameter function will locate the element by the id passed and will populate the value of that element in the parameter list. The addRequestParameterAndValue will let you add parameters to the request for elements that may not exist on the page. The addCallback function will be returned back to the client by the application server in the action list. Finally, postRequest will send the request off to the server.

I won't pull up all of the SimpleAsynch.js code here. You can get it from the site.

On the server you would process the request and build a response. Here's an example where we're trying to populate the screen with the details of a requirement. This example shows the construction of the xml using the SimpleAsynch ResponseXml class. ResponseXml uses a django template to construct the XML for the response.


class LoadRequirement(webapp.RequestHandler):
def post(self):
requirementId = self.request.get('requirementId')
requirements_query = db.GqlQuery("SELECT * FROM Requirement where requirementId = :1",
int(requirementId))
requirements = requirements_query.fetch(1)

rx = ResponseXml()

for requirement in requirements:
rx.addAction("input","requirementIdHidden",str(requirement.requirementId))
rx.addAction("input","requirementNumber",str(requirement.requirementNumber))
rx.addAction("input","listRequirementNumber",str(requirement.requirementNumber))
rx.addAction("input","requirementSubNumber",str(requirement.subNumber))
rx.addAction("input","requirementVersion",str(requirement.version))
rx.addAction("input","requirementMaxVersionHidden",str(requirement.maxVersion))
rx.addAction("input","requirementSummary",requirement.summary)
rx.addAction("input","requirementDescription",requirement.description)
rx.addAction("input","requirementComments",requirement.comments)
rx.addAction("input","requirementStatus",requirement.status)
labelString = ""
for label in requirement.labels:
labelString = label " "
rx.addAction("input","requirementLabels",labelString)
rx.addAction("input","requirementAuthor",str(requirement.requirementAuthor))
rx.addAction("input","requirementEntered",requirement.entered.strftime("%m/%d/%y %H:%M"))
rx.addAction("callback",self.request.get("callback"),"")
if rx.getLength()==0:
rx.addAction("alert","Requirement was not found.","")
self.response.out.write(rx.getXml())

0 comments 16 views
comments
name
email
comment
 User
top comments
 
top views
 
top tags
 
favorite sites