Introduction to Ajax for PHP Web Applications

You must define the callback function to handle the server’s response, and add any functionality necessary to reflect changes in the page that is viewed by the user. This requires modifying the HTML DOM. Finally, you can work in the IDE’s CSS Editor to add a simple stylesheet to the presentation.

Notice that the parseMessages() function is called only when the XMLHttpRequest.readyState is “4” and the status — the HTTP status code definition of the request — is “200”, signifying a success. You will define parseMessages() next in Updating the HTML DOM .

A readyState of “4” signifies the completion of the HTTP interaction. The API for XMLHttpRequest.readState indicates that there are 5 possible values that can be set. These are:

The callback function is called asynchronously at specific points during HTTP interaction when the readyState property of the XMLHttpRequest object changes. In the application you are building, the callback function is callback() . You recall that in doCompletion() , callback was set as the XMLHttpRequest.onreadystatechange property to a function. Now, implement the callback function as follows.

Updating the HTML DOM

The parseMessages() function handles the incoming XML data. In doing so, it relies on several ancillary functions, such as appendComposer(), getElementY(), and clearTable(). You must also introduce new elements to the index page, such as a second HTML table which serves as the auto-complete box, and ID’s for elements so they can be referenced in javascript.js. Finally, you create new variables corresponding to ID’s for elements in index.php, initialize them in the init() function that you previously implemented, and add some functionality that is needed each time index.php is loaded.

The functions and elements that you create in the following steps work interdependently. It is recommended that you work through this section, then examine the code once it is all in place.

  1. Open index.html in the editor and type in the below code for the second row of the HTML table you previously created.

<tr>
    *<td id="auto-row" colspan="2">

    <td/>*
</tr>

This new row, which can be identified as ‘auto-row’, serves as a handle for the JavaScript code in order to insert a new HTML table that will form the auto-complete box.

  1. Open javascript.js in the editor and the following three variables to the top of the file.

var completeField;
var completeTable;
var autoRow;
  1. Add the following lines (in bold) to the init() function.

function init() {
    completeField = document.getElementById("complete-field");
    *completeTable = document.createElement("table");
    completeTable.setAttribute("class", "popupBox");
    completeTable.setAttribute("style", "display: none");
    autoRow = document.getElementById("auto-row");
    autoRow.appendChild(completeTable);
    completeTable.style.top = getElementY(autoRow) + "px";*
}

One purpose of init() is to make elements inside index.html accessible to other functions that will modify the index page’s DOM. Above, the script creates a new HTML table, adds the popupBox class and modifies the element’s style to display: none. Finally, it gets the element whose id is auto-row and inserts the new table into it. In other words, the modified HTML looks as follows when the code is run.

<tr>
    <td id="auto-row" colspan="2">
        *<table class="popupBox" style="display: none"></table>*
    <td/>
</tr>
  1. Add appendComposer() to javascript.js.

function appendComposer(firstName,lastName,composerId) {

    var row;
    var cell;
    var linkElement;

    if (isIE) {
        completeTable.style.display = 'block';
        row = completeTable.insertRow(completeTable.rows.length);
        cell = row.insertCell(0);
    } else {
        completeTable.style.display = 'table';
        row = document.createElement("tr");
        cell = document.createElement("td");
        row.appendChild(cell);
        completeTable.appendChild(row);
    }

    cell.className = "popupCell";

    linkElement = document.createElement("a");
    linkElement.className = "popupItem";
    linkElement.setAttribute("href", "autocomplete.php?action=lookup&amp;id=" + composerId);
    linkElement.appendChild(document.createTextNode(firstName + " " + lastName));
    cell.appendChild(linkElement);
}

This function creates a new table row, inserts a link to a composer into it using the data passed to the function via its three parameters, and inserts the row into the index page’s complete-table element.

  1. Add clearTable() to javascript.js.

function clearTable() {
    if (completeTable.getElementsByTagName("tr").length > 0) {
        completeTable.style.display = 'none';
        for (loop = completeTable.childNodes.length -1; loop >= 0 ; loop--) {
            completeTable.removeChild(completeTable.childNodes[loop]);
        }
    }
}

This function sets the display of the complete-table element to ‘none’, (i.e., makes it invisible), and it removes any existing composer name entries that were created.

  1. Add getElementY() to javascript.js.

function getElementY(element){

    var targetTop = 0;

    if (element.offsetParent) {
        while (element.offsetParent) {
            targetTop += element.offsetTop;
            element = element.offsetParent;
        }
    } else if (element.y) {
        targetTop += element.y;
    }
    return targetTop;
}

This function is applied to find the vertical position of the parent element. This is necessary because the actual position of the element, when it is displayed, is often dependent on browser type and version. Note that the complete-table element, when displayed containing composer names, is shifted to the lower right of the table in which it exists. The correct height positioning is determined by getElementY().

See this explanation of offset on http://www.quirksmode.org/.

  1. Modify the callback() function to call clearTable() each time new data is received from the server. Any composer entries that already exist in the auto-complete box are therefore removed before it becomes populated with new entries.

function callback() {

    *clearTable();*

    if (req.readyState == 4) {
        if (req.status == 200) {
            parseMessages(req.responseXML);
        }
    }
}
  1. Add parseMessages() to javascript.js.

function parseMessages(responseXML) {

    // no matches returned
    if (responseXML == null) {
        return false;
    } else {

        var composers = responseXML.getElementsByTagName("composers")[0];

        if (composers.childNodes.length > 0) {
            completeTable.setAttribute("bordercolor", "black");
            completeTable.setAttribute("border", "1");

            for (loop = 0; loop < composers.childNodes.length; loop++) {
                var composer = composers.childNodes[loop];
                var firstName = composer.getElementsByTagName("firstName")[0];
                var lastName = composer.getElementsByTagName("lastName")[0];
                var composerId = composer.getElementsByTagName("id")[0];
                appendComposer(firstName.childNodes[0].nodeValue,
                    lastName.childNodes[0].nodeValue,
                    composerId.childNodes[0].nodeValue);
            }
        }
    }
}

The parseMessages() function receives as a parameter an object representation of the XML document returned by the autocomplete.php file. The function programmatically traverses the XML document, extracting the firstName, lastName, and id of each entry, then passes this data to appendComposer(). This results in a dynamic update to the contents of the complete-table element. For example, an entry that is generated and inserted into complete-table might look as follows:

<tr>
    <td class="popupCell">
        <a class="popupItem" href="autocomplete?action=lookup&amp;id=12">Antonin Dvorak</a>
    </td>
</tr>

The dynamic update to the complete-table element represents the final step of the process flow of communication that takes place during communication using Ajax. This update maps to the HTML & CSS data being sent to the presentation in the flow diagram above.