Response Handling

Chapter 5 12 mins

Learning outcomes:

  1. Handling text files
  2. Handling JSON data
  3. Handling XML files

Introduction

Upto this point we've seen numerous concepts in working with AJAX, but quite not yet seen how to retrieve the response data from a requested file and work with it.

In this chapter we shall get a rigorous understanding of how to deal with AJAX responses, using the responseText and responseXML properties, how to parse XML documents into a DOM tree and how to generally work with all sort of responses whatsoever. Let's begin to handle responses.

A quick recap

Before beginning, take a minute or two to review the complete code we developed in the previous chapter to fetch a file using AJAX.

var xhr = new XMLHttpRequest();
xhr.open("GET", "ajax.txt", true);

xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        // request completed and a successful response
        // we will work here
    }
}

xhr.send();

It had an event - onreadystatechange - to hear for state changes, and within it a check for readyState == 4 to confirm request completion and a check for status == 200 to confirm a successful fetch.

All our further discussion will be based on this simple piece of code so just make sure you are well versed with it, before moving on.

Response as text

Consider a text file named foods.txt with the following content:

Pizza
Chocolate
Mango
Cake

We'll making an AJAX request to fetch this file and finally display its content to the document, once received completely and successfully.

Recall from the AJAX States chapter, that once readyState becomes equal to 4, the response of a given request is ready to be worked with. One way we can work with it is using responseText.

The responseText property is filled up by the browser automatically once the request goes to completion, at state 4. It contains the content of the response i.e whatever the server sends apart from the headers, as a text value, or in other words, as a string. Hence the name responseText.

For the case of the foods.txt file above, once it is successfully received at the client end, responseText will become equal to its actual content shown above.

And once inside responseText, we can literally do anything with the response data such as parsing it, extracting information out of it; maybe even displaying the result which is the case most often.

Following we output the content of foods.txt, at the click of a button, making it all more interesting. The button simply serves to dispatch the request we create previously in the code. For simplicity we've assumed that the button invokes a function sendRequest() on its click.

var xhr = new XMLHttpRequest();
xhr.open("GET", "foods.txt", true);

xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        document.write(this.responseText);
    }
}

// button's onclick handler function
function sendRequest() {
    xhr.send();
}

Live Example

After the button is clicked and as soon as the content is received completely, document.write() comes into action printing responseText to the document. Implement this example on your own and witness a very basic example of what AJAX can do!

Now this was a very basic example demonstrating the fetch of a plain text file, but what if we have an XML or HTML file to be brought into the game?

Well we can use responseXML for these cases as we will see later, but before that there is yet another file type that goes well with textual representations i.e JSON.

Working with JSON

JSON stands for JavaScript Object Notation, and is one of the most popular and easy-to-use data interchange formats widely supported across numerous programming languages. In this section we will look into working with JSON files.

Consider the following snippet showing the content of the food.json file.

{
    "name": "Pizza",
    "price": 6.50
}

We'll fetch this using the same procedure as discussed above and then afterwards use JSON.parse to convert the response (from a string) into a JavaScript object.

In the code below we print responseText to the document as it is, in textual format:

var xhr = new XMLHttpRequest();
xhr.open("GET", "food.json", true);

xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        document.write(this.responseText);
    }
}

// button's onclick handler function
function sendRequest() {
    xhr.send();
}

Live Example

Now we will utilise the power of JSON and convert this response into an object using JSON.parse(). Following we save the parsed object into the variable food and then use its two properties, as written in food.json:

xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        var food = JSON.parse(this.response);
        document.write("Name: " + food.name + "<br>");
        document.write("Price: " + food.price);
    }
}

Live Example

The benefit of this conversion is that we can use the object just like any other JavaScript object, with properties and methods - at the end it's also an object!

Much more complex use cases of JSON can be present in a real world application involving hundreds, or maybe even thousands, of items and deep levels of nesting. A very simple example is shown below.

Consider the JSON file foods.json shown below, consisting of details about a variety of foods.

[{
    "name": "Pizza",
    "price": 6.50
},
{
    "name": "Mango",
    "price": 1.00
},
{
    "name": "Chocolate",
    "price": 3.00
}]

Your task is to fetch this using AJAX and ultimately print out details for each food in the format "{name} is for ${price}" on a newline.

For example for the first food you shall print "Pizza is for $6.50".

All the code will remain the same except for the code inside the if statement where we will have to loop over the parsed JSON object. Notice the fact that it will be an array and so we could simply use a normal loop to print each food's details.

var xhr = new XMLHttpRequest();
xhr.open("GET", "foods.json", true);

xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        var foods = JSON.parse(this.responseText);
        for (var i = 0; i < foods.length; i++) {
            document.write(foods[i].name + " is for $" + foods[i].price.toFixed(2) + "<br>");
        }
    }
}

xhr.send();

Although the question didn't say so, we've implemented this task as a click-driven AJAX application similar to the examples shown above. Moreover you'll notice the method toFixed() in the code above and may not be able to reason for its use here.

It is only used to get the values 6.50, 3.00 remain as they are written in the JSON file. JavaScript trims unneccessary zeros from numbers, and so get the desired result we have to force in zeros after the decimal point using toFixed(). You can discover more details at JavaScript Number Methods.

JSON Foods

Dealing with XML

Back in the time, when XMLHttpRequest() was created and standardised the main format for information interchange was XML. Likewise it makes sense that the community would've thought of some way to be able to parse the requested XML documents for ease of use, doesn't it?

The property responseXML was thus created to hold the requested XML documents as parsed DOM trees, easy to traverse through and, as a whole, work with.

Unlike responseText which simply holds a textual format of an XML response, responseXML gives you an object to play around with - an object with tons of properties and methods and traversable functionalities.

Consider a simple XML file named foods.xml shown as follows:

<?xml version="1.0" encoding="UTF-8" ?>
<foods>
    <food>
        <name>Pizza</name>
        <price>6.50</price>
    </food>
    <food>
        <name>Mango</name>
        <price>1.00</price>
    </food>
</foods>

As before, the code to fetch this file will, more or less, remain the same as the AJAX codes shown above. By this point setting up this basic code shall be at your fingertips; if it's not then you shall go back and review your foundational concepts.

Following we process this file using responseText and display the result to the document:

var xhr = new XMLHttpRequest();
xhr.open("GET", "foods.xml", true);

xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        document.body.innerText = this.responseText;
    }
}

xhr.send();
Notice here that we've not used document.write() to print the response, but instead the innerText property on document.body. This is done because document.write() parses any tags inside its string argument and will therefore also parse the tags such as <food>, <name> etc. in resposeText from our XML file.

Live Example

As you might've realised from the live example, this text response is not really that useful when dealing with large XML files. Thereby now we will bring on the real player into the game i.e responseXML and see what can it do for us.

Following we loop over all the food items in our XML file and output details for each one as we do so.

var xhr = new XMLHttpRequest();
xhr.open("GET", "foods.xml", true);

xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        var xmlDom = this.responseXML;
        var foods = xmlDom.getElementsByTagName("food");
        for (var i = 0; i < foods.length; i++) {
            document.write("Name: " + foods[i].getElementsByTagName("name")[0].textContent + "<br>");
            document.write("Price: " + foods[i].getElementsByTagName("price")[0].textContent + "<br><br>");
        }
    }
}

xhr.send();

If you are familiar with HTML DOM in JavaScript then you'll find no problems, at all, in understanding this piece of code.

The variable foods holds a collection of all <food> elements which we iterate over in the next for loop. Inside the loop, for each element, we select its <name> and <price> tags and retrieve their respective values. These are then written to the document using documet.write().

Live Example

XML is amazing both in terms of its ease to use and ease to understand. It's a lightweight, compact, comprehensive and common information interchange format around the web serving tons of purposes. Not only this but it even has a dedicated functionality in XMLHttpRequest() to be able to parse it i.e using the responseXML property.

In short, if you are to work with XML in AJAX you are in a good company!