Chapter 34. Making Ajax Requests Using POST

If GET requests make up the majority of HTTP requests on the Web, POST requests come in second. POST requests are typically generated by forms. While not every form sends its data using the POST method, many are used to POST information to the server.

POST requests are the exact opposite of GET requests: They are used to submit data to a web application so the application can do something with that data. The request's data is sent in the request's body, unlike with GET requests, in which data can be sent in the URL's query string. Despite these differences, making POST requests with XMLHttpRequest (XHR) objects is strikingly similar to making GET requests. There are, of course, some differences, and you'll learn about them in this lesson.

ASSEMBLING DATA

POST requests are designed to send information from the browser to the server. Because of this the majority of POST requests are made through forms. Forms are the primary means by which users input and send data. The difference with Ajax, however, is in how that data is sent.

Without Ajax, the browser is responsible for gathering the form's data, formatting it, and POSTing it to the server. With Ajax, that responsibility falls to you. So before sending a POST request you must assemble the form's data and format it.

Let's look at an example form:

<form name="theForm" method="post" action="ajax_test.php">
    <p>
        Name: <input type="text" name="txtName" value="" />
    </p>
    <p>
        Email: <input type="text" name="txtEmail" value="" />
    </p>
<p>
        <input type="submit" name="btnSubmit" value="Submit" />
    </p>
</form>

This form has two textboxes: one for a name and one for an e-mail address. It also has a button to submit the form, and the form POSTs to a file on the server called ajax_test.php.

Note

PHP is a programming language and server-side framework that allows developers to write server-side programs. It runs on virtually every operating system. Explaining PHP is beyond the scope of this book, but I use it in examples. Refer to Lesson 31 on the DVD for installation instructions for Windows and Mac OS X.

If a user enters the value Jeremy in the name textbox and jeremy@xyz in the e-mail textbox, the browser assembles the data into the following format when the user clicks the submit button:

txtName=Jeremy&txtEmail=jeremy%40xyz.com&btnSubmit=Submit

This looks very much like the query portion of a URL. There are three name/value pairs separated by ampersands (&). They are:

  • txtName=Jeremy

  • txtEmail=jeremy%40xyz.com

  • btnSubmit=Submit

On the left side of each equals sign (=) is the name of a form control from the form, and on the right side is the value of that control. Notice the value of txtEmail. Instead of , it's jeremy%40xyz.com. The @ symbol is a special character that has its own meaning in HTTP, and it must be encoded before being transmitted as part of a request's body. Other special characters are:

  • , (comma)

  • /

  • ?

  • :

  • &

  • =

  • +

  • $

  • #

When you are POSTing data to a server with XHR, the request's body must be in this format. Having to assemble and format all the information contained within a form may sound daunting, but a function can do it all for you. Look at the beginnings of a function called getRequestBody() in the following code:

function getRequestBody(form) {
    var pieces = [];
    var elements = form.elements;

    // more code here

    return pieces.join("&");
}

This function accepts one argument, a <form/> element object. So you can pass the function any form and have it generate the body for a request. The first two statements in this function create two variables. The first is an array called pieces, and each element in this array will be a name/value pair. The second variable, elements, is assigned the form's elements collection property. The final line of this function returns the result of calling the pieces array's join() method.

Next, the function loops through the elements collection and constructs a name=value string for each form control. The new code is in bold:

function getRequestBody(form) {
    var pieces = [],
        elements = form.elements;

    for (var i = 0; i < elements.length; i++) {
        var element = elements[i];
        var name = encodeURIComponent(element.name);
        var value = encodeURIComponent(element.value);

        pieces.push(name + "=" + value);
    }

    return pieces.join("&");
}

Inside the for loop three new variables are initialized. The first variable, element, contains the form control element object as the specified index. The second variable, name, is assigned an encoded version of the element's name property by passing the un-encoded property to the encodeURIComponent() function. The encodeURIComponent() function is a built-in function that encodes special characters into their transmittable equivalents. The third variable, value, is assigned an encoded version of the form control's value property. Finally, the name and value variables are concatenated and added to the pieces array.

Now you can assemble and format a form's contents by simply calling this function and passing it the <form/> element object you want to send, like this:

var requestBody = getRequestBody(document.theForm);

This code passes the form with the name theForm to the getRequestBody() function to generate properly formatted data and assign it to the requestBody variable.

Warning

The getRequestBody() function, as written in this lesson, does not take into account disabled fields, unchecked radio and check boxes, or <select/> elements.

MAKING POST REQUESTS

After you have data in the appropriate format, you can send it with an XHR object. POST requests look a lot like GET requests, so the following code will look familiar to you:

var xhr = createXHR();
var data = getRequestBody(document.theForm);

xhr.open("POST", "ajax_test.php");
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) {
        var status = xhr.status;
        if ((status >= 200 && status < 300) || status === 304) {
            processResponse(xhr.responseText); // callback function
        } else {
            alert("An error occurred");
        }
    }
};

xhr.send(data);

The first major change is the addition of the data variable, and it contains a formatted string of name/value pairs to send in the request. The next big change is in the call to the open() method: The first argument is now POST instead of GET. After the call to open() is a new line of code that calls the XHR object's setRequestHeader() method. This method allows you to set an HTTP header with a supplied value. In the case of POST requests you need to set the Content-Type header with the value application/x-www-form-urlencoded. Otherwise the request will not work. The last major change is in the call to send(). Instead of passing null you pass the data generated by getRequestBody().

Note

Setting the Content-Type header to application/x-www-form-urlencoded is not necessary for all POST requests—it is only required when sending form-formatted data.

You can simplify POST requests by writing a function like the makeGetRequest() function you wrote in Lesson 33. The following code defines a function called postFromForm():

function postFromForm(url, form, callback) {
    var xhr = createXHR();
    var data = getRequestBody(form);

    xhr.open("POST", url);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
            var status = xhr.status;
            if ((status >= 200 && status < 300) || status === 304) {
                callback(xhr.responseText);
            } else {
                alert("An error occurred");
            }
        }
    };

    xhr.send(data);
}

This function accepts three arguments: the URL to request, the <form/> object that you want to gather data from, and the callback function to execute when the request completes successfully. So using this function means writing something like the following code:

function processResponse(responseData) {
    alert(responseData);
}

postFromForm("ajax_text.php", document.theForm, processResponse);

Here, a POST request containing the data from a form named theForm is sent to ajax_text.php, and on a successful request, the processResponse() function processes the server's response.

TRY IT

In this lesson, you learn how to make POST requests using XHR objects by formatting the request body's data, supplying the Content-Type header, and sending data with the request.

Lesson Requirements

For this lesson, you need a text editor; any plain text editor will do. For Microsoft Windows users, Notepad is available by default on your system or you can download Microsoft's free Visual Web Developer Express (www.microsoft.com/express/web/) or Web Matrix (www.asp.net/webmatrix/). Mac OS X users can use TextMate, which comes as part of OS X, or download a trial for Coda (www.panic.com/coda/). Linux users can use the built-in VIM.

You also need a modern web browser. Choose any of the following:

  • Internet Explorer 8+

  • Google Chrome

  • Firefox 3.5+

  • Apple Safari 4+

  • Opera 10+

Additionally, you need webserver software and PHP installed on your computer. Refer to Lesson 31 on the DVD for installation instructions. Create a subfolder called Lesson34 in the root directory of your webserver. Store the files you create in this lesson in the Lesson34 folder.

Step-by-Step

  1. Copy the ajax_post.php file from the code download to the Lesson34 directory. This is a PHP file that generates random messages based on the information POSTed to it.

  2. Write an Ajax utility object. Create a new file called ajaxUtility.js and type the following:

    var ajaxUtility = {
        createXHR : function() {
            if (typeof XMLHttpRequest !== "undefined") {
                return new XMLHttpRequest();
            } else {
                var versions = [ "MSXML2.XmlHttp.6.0",
                    "MSXML2.XmlHttp.3.0" ];
    
                for (var i = 0; i < versions.length; i++) {
                    try {
                        var xhr = new ActiveXObject(versions[i]);
                        return xhr;
                    } catch (error) {
                        // do nothing
                    }
                }
            }
    
            alert("Your browser does not support XmlHttp");
    
            return null;
        },
    
        makeGetRequest : function(url, callback) {
            var xhr = this.createXHR();
    
            xhr.open("GET", url);
    
            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4) {
                    var status = xhr.status;
    if ((status >= 200 && status < 300) || status === 304) {
                        callback(xhr.responseText);
                    } else {
                        alert("An error occurred");
                    }
                }
            };
    
            xhr.send(null);
        },
    
        getRequestBody : function(form) {
            var pieces = [];
            var elements = form.elements;
    
            for (var i = 0; i < elements.length; i++) {
                var element = elements[i];
                var name = encodeURIComponent(element.name);
                var value = encodeURIComponent(element.value);
    
                pieces.push(name + "=" + value);
            }
    
            return pieces.join("&");
        },
    
        postFromForm : function(url, form, callback) {
            var xhr = this.createXHR();
            var data = this.getRequestBody(form);
    
            xhr.open("POST", url);
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    
            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4) {
                    var status = xhr.status;
                    if ((status >= 200 && status < 300) || status === 304) {
                        callback(xhr.responseText);
                    } else {
                        alert("An error occurred");
                    }
                }
            };
    
            xhr.send(data);
        }
    };

    This code creates a new object called ajaxUtility. Its createXHR() and makeGetRequest() methods resemble the functions of the same name from the xhr.js file. The other two methods, getRequestBody() and postFromForm(), are the same as the two functions of the same name from this lesson. Creating a utility like this is advantageous because it keeps all code grouped together in the ajaxUtility object.

  3. Copy the eventUtility.js file from the Lesson33 directory to the Lesson34 directory.

  4. Type the following HTML:

    <html>
    <head>
        <title>Lesson 34: Example 01</title>
    </head>
    <body>
    <form name="theForm" method="post" action="ajax_post.php"
    onsubmit="addUser(event)">
        <p>
            Name: <input type="text" name="txtName" value="" />
        </p>
        <p>
            Email: <input type="text" name="txtEmail" value="" />
        </p>
        <p>
            <input type="submit" name="btnSubmit" value="Submit" />
        </p>
    </form>
    <script type="text/javascript" src="eventutility.js"></script>
    <script type="text/javascript" src="ajaxUtility.js"></script>
    <script type="text/javascript">
    
    </script>
    </body>
    </html>

    This page contains the same form from earlier in this lesson, but it POSTs to ajax_post.php and has an onsubmit event handler. The eventUtility.js and ajaxUtility.js files are also added to the page via two <script/> elements, with a third <script/> element that will contain inline JavaScript code.

  5. The form's onsubmit event handler calls the addUser() function. This function should verify that the form is filled out and should POST to the ajax_post.php file. Type the following function inside the empty <script/> element:

    function addUser(event) {
        var theForm = document.theForm;
        var name = theForm.txtName.value;
        var email = theForm.txtEmail.value;
        var button = theForm.btnSubmit;
    
        button.disabled = true;
    
        if (name === "" || email === "") {
            alert("Please complete the form.");
            button.disabled = false; // so user can resubmit
        } else {
            ajaxUtility.postFromForm(theForm.action, theForm, processData);
        }
    
        eventUtility.preventDefault(event);
    }

    This function first disables the submit button to prevent the user from submitting more than one request at a time. Then the function determines if the textboxes contain information and asks the user to complete the form if either textbox is empty. If both textboxes contain data you pass the theForm object to the ajaxUtility.postFromForm() method to send the request.

    Instead of the string literal ajax_post.php's being passed to the postFromForm() method, the form's action property is used instead. This is a nice little technique that allows your XHR object to POST data to whatever URL is specified within the <form/> element's action attribute. So if you change the value of the action attribute you don't have to change the URL in the call to postFromForm().

    Finally, the event utility's preventDefault() method prevents the form from being submitted.

  6. Write the processData() function. All it needs to do is alert the response data and re-enable the button. Type the following function inside the inline <script/> element:

    function processData(data) {
        var button = document.theForm.btnSubmit;
    
        alert(data);
    
        button.disabled = false;
    }

Save the file as lesson34_example01.htm, and point your browser to http://localhost/Lesson34/lesson34_example01.htm. Fill out the form, submit it, and watch the random responses from the server.

Note

Please select Lesson 34 on the DVD to view the video that accompanies this lesson.

Step-by-Step
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.143.254.151