In an earlier entry, Missing Data After AJAX Call, I threw a hack together to return multiple values which required parsing based on a separator on the client side.
After testing, I realized using a character as a separator is a bad idea. The data returned could have the character as part of its value and screw up the parsing later on the client side. Storing the data as XML and returning the data as such makes for a more elegant solution.
I also wanted to send a large amount of text through AJAX and the GET request was not getting the job done. Using POST instead of GET works well; the reason behind it is similar to why it works for forms or forum postings.
Talking about the what’s and why’s does not make it very clear. That is why I brought an example with me including the corresponding code. w00t!
On messageboards, the posting form usually has a preview button which directs the user to a new page to see how their post would look after submission. Upon submission, there may be a validation script that runs to check for missing fields or whatnot. Rather than reloading the page for each of these actions, we can use AJAX to do both at once!
The Plan:
- User fills out form.
- User clicks Preview button.
- Click triggers call to JavaScript function.
- Function retrieves form values.
- Function sends values to PHP script.
- PHP script returns an XML file.
- Function parses XML file.
- Function updates page on screen.
- User rejoices.
Step 1: Create the form.
Add the function call on the preview button. This would also be a good time to add the preview and error divs for the returned data.
Step 2: Create the JavaScript function.
The GetXmlHttpObject() function is just activating the HTTP request. The code can be found on pretty much every AJAX tutorial. The URL is pointing to your script. The param variable holds the URL parameters. I ran the values through the encodeURI function to stop potential intrusions.
function preview_message() {
request = GetXmlHttpObject();
if (request==null) {
alert ("Your browser does not support AJAX!");
return;
}
var url = "preview.php";
var param = "";
param += "&title="+encodeURI(document.comment.title.value);
param += "&mesg="+encodeURI(document.comment.message.value);
When opening the request, use POST instead of GET. Then send the parameters via the send function rather than leaving it null as you would usually do for a GET request.
request.onreadystatechange = display_preview;
request.open("POST", url, true);
request.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
request.setRequestHeader("Content-length", param.length);
request.setRequestHeader("Connection", "close");
request.send(param);
}
Step 3: Create the PHP script.
Access the sent parameters the same way as if a form was submitted via POST.
$title = urldecode(trim($_POST["title"]));
$mesg = urldecode(trim($_POST["mesg"]));
Create the XML object for the validation checks.
$error = "";
if (strcmp($title,"") == 0) {
$error .= "";
$error .= "Title is missing. ";
$error .= "FF0000 ";
$error .= " ";
}
if (strcmp($mesg,"") == 0) {
$error .= "";
$error .= "Message is missing. ";
$error .= "FF0000 ";
$error .= " ";
}
Strip unwanted HTML tags from the title and message for security reasons and store the results in it’s own XML module.
$title = strip_tags($title);
$mesg = strip_tags($mesg);
$comment = "";
$comment .= "{$title} ";
$comment .= "{$mesg} ";
$comment .= " ";
Now, finish constructing the XML and print out the results. Don’t forget to include the necessary headers indicating the data will be XML. I am not sure if the no-cache is needed but I didn’t want any screw ups from returning old data.
header("Content-Type: text/xml");
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
echo '';
echo $error;
echo $comment;
echo ' ';
Step 4: Parse XML using JavaScript.
I was actually stuck on this part for quite a long time. I am not very familiar with XML nor the steps needed to traverse the XML tree.
Grab the divs for the error and message parts.
var preview_div = document.getElementById("preview_div");
var error_div = document.getElementById("error_div");
Retrieve the response from the PHP script. Since we returned the data in XML format, we needed to retrieve using .responseXML rather than the usual .responseHTML. Using the getElementsByTagName() function, we can grab the XML objects based on their tag names.
var xmldoc = request.responseXML;
var errors = xmldoc.getElementsByTagName("error");
var preview = xmldoc.getElementsByTagName("preview");
Since there could be multiple errors, we first determine the amount and then loop through to retrieve the child nodes. Then replace the innerHTML of the error div with the result.
var errors_length = errors.length;
for (i=0; i";
error += errors[i].getElementsByTagName("message")[0].childNodes[0].nodeValue;
error += "";
if (i ";
}
}
error_div.innerHTML = error;
We do the same for the preview results only if there were no errors.
if (error_length == 0) {
var title = preview[0].getElementsByTagName("title")[0].childNodes[0].nodeValue;
var message = preview[0].getElementsByTagName("message")[0].childNodes[0].nodeValue;
preview_div.innerHTML = "Title: "+title+"
Message: "+message;
}
There we have it. Using POST to send large volumes of data and returning multiple values via XML.
Step 4 belongs in the display_preview() function along with the checks for the readystate. It’s pretty late now and I don’t have the energy to fill that part out.