As I have written in my
last post I am currently experimenting with AJAX for VoiceXML. Today, I finished my first spike on that topic and I think it is worth sharing.
My idea was to use AJAX to asynchronously 'push' updated data from the server to the client in order to prompt the user with it, i.e. doing pretty much the same thing a web developer would do for the visual web when 'pushing' data from the server to the web browser. AJAX has all the nice features in place to realize the client-server communication and since XHTML+Voice lets us call VoiceXML prompts from within JavaScript code we can integrate AJAX with VoiceXML in a straight forward way:
Step One: Remembering the Last Server ResponseIn the head of our XHTML document we will define the following JavaScript code. Our global variable ajax_response will be used to contain the most current response from the remote server. old_ajax_response will save a previous copy of ajax_response that will be used to see if the content delivered by the server has changed. Some words on this later.
var ajax_response = '';
var old_ajax_response = '';
Next, we will provide a simple getter for ajax_response:
function getPrompt(){
return ajax_response;
}
Step Two: The VoiceXML Output FormSince we are interested in presenting the updated server data to the user, we will use a simple VoiceXML form containing a simple prompt:
<form xmlns="http://www.w3.org/2001/vxml" id="myPrompt">
<block>I have just received an update for you
<value expr="getPrompt();">
</value>
</block>
</form>
The form simply asks the getPrompt() method for the latest data that has been received from the server and uses it to prompt the user.
Step Three: Simulating Server PushNext, we need a method for making a request to our remote JSP script that is generating the server-side content.
function makeRequest() {
var url = 'my_ajax_example.jsp';
var http_request = false;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
http_request = new XMLHttpRequest();
if (http_request.overrideMimeType) {
http_request.overrideMimeType('text/xml');
}
} else if (window.ActiveXObject) { // IE
try {
http_request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
http_request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
if (!http_request) {
alert('Giving up :( Cannot create an XMLHTTP instance');
return false;
}
http_request.onreadystatechange = function() { myHandler(http_request); };
http_request.open('GET', url, true);
http_request.send(null);
}
The last function we need is the myHandler callback function that has been used in the above AJAX call. This simple method has the real magic in it. When the data that arrives from the server is new to the client, it uses the DOMActivate event to activate the myPrompt form.
function myHandler(http_request) {
if (http_request.readyState == 4) {
if (http_request.status == 200) {
ajax_response = http_request.responseText;
if (old_ajax_response != ajax_response) {
old_ajax_response = ajax_response;
var e = document.createEvent("UIEvents");
e.initEvent("DOMActivate","true","true");
document.getElementById('myPrompt').dispatchEvent(e);
}
} else {
ajax_response = 'There was a problem with the request.';
}
}
}
Step Four: Initializing the Polling ProcedureNow we have almost everything we need: We have the JavaScript in place that asks the server for an update, we know how to include this data in a VoiceXML form and now all that's left is telling the browser to poll the server for an update using an interval of our choice. We need to do this, because we are just
simulating server push. Our client still needs to poll the server in order to receive updated data. This is done by adding the following line of JavaScript code to the above JS code, which is going to call the makeRequest method every ten seconds:
var theTimer = setInterval("makeRequest()", 10000);
ConclusionThe presented example shows how AJAX can be used to simulate a server push voice dialogue to the user. It is a proof-of-concept, nothing more. If you are going to use this for your applications you should make sure to only send as much data to the client as necessary. The example always loads a complete data fragment and compares it to the last one received. This is not network efficient, though. Incremental updates might be a better idea for your application.
AcknowledgementThis example is based on AJAX code snippets from an
introductory article by great people at Mozilla (code used under
MIT License). DOMActivate for use in VoiceXML forms is described in
section 4.2.1 of the
XHTML+Voice Profile 1.2 note at VoiceXML.org.