Wrox Home  
Search
Professional Ajax
by Nicholas C. Zakas, Jeremy McPeak, Joe Fawcett
March 2007, Paperback


Drawing the Results User Interface

The code to generate this HTML is rather lengthy because the elements are generated using DOM methods. The drawResultBox() method accepts one argument, an event object:

msnWebSearch.drawResultBox = function (e) {
    var divSearchBox= document.createElement("div");
    var divHeading = document.createElement("div");
    var divResultsPane = document.createElement("div");
    var aCloseLink = document.createElement("a");

These first lines create the HTML elements via the createElement() method. After the elements have been created, you can begin to assign their properties. The first two elements to finalize are aCloseLink and divHeading:

aCloseLink.href = "#";
aCloseLink.className = "ajaxWebSearchCloseLink";
aCloseLink.onclick = this.close;
aCloseLink.appendChild(document.createTextNode("X"));
    
divHeading.className = "ajaxWebSearchHeading";
divHeading.appendChild(document.createTextNode("MSN Search Results"));
divHeading.appendChild(aCloseLink);

The first four lines complete the link that closes the result box. A method, close(), becomes the handler for the link's onclick event. The next group of lines populate the heading <div/> with text and the closing link.

When this result box is drawn into the page, a response from the server application has not been received yet. To show the user that something is happening (other than a box popping out of nowhere), it would be nice for the user to see a message stating that data is loading (see Figure 2). To do this, create another element and append it to the divResultsPane element:

var divLoading = document.createElement("div");
divLoading.appendChild(document.createTextNode("Loading Search Feed"));
    
divResultsPane.className = "ajaxWebSearchResults";
divResultsPane.appendChild(divLoading);

This code creates the loading message and appends it to divResultsPane, while also assigning the class name to divResultsPane.


Figure 2

With these elements completed, all that remains is to add them to the divSearchBox element:

divSearchBox.className = "ajaxWebSearchBox";
divSearchBox.appendChild(divHeading);
divSearchBox.appendChild(divResultsPane);
document.body.appendChild(divSearchBox);

This code appends the divHeading and divResultsPane elements to the search box, and appends the search box to the page.

The final step in drawResultBox() is to position the newly drawn box and return divSearchBox to its caller:

msnWebSearch.drawResultBox = function (e) {
    var divSearchBox= document.createElement("div");
    var divHeading = document.createElement("div");
    var divResultsPane = document.createElement("div");
    var aCloseLink = document.createElement("a");
    
    aCloseLink.href = "#";
    aCloseLink.className = "ajaxWebSearchCloseLink";
    aCloseLink.onclick = this.close;
    aCloseLink.appendChild(document.createTextNode("X"));
    
    divHeading.className = "ajaxWebSearchHeading";
    divHeading.appendChild(document.createTextNode("MSN Search Results"));
    divHeading.appendChild(aCloseLink);
    
    var divLoading = document.createElement("div");
    divLoading.appendChild(document.createTextNode("Loading Search Feed"));
    
    divResultsPane.className = "ajaxWebSearchResults";
    divResultsPane.appendChild(divLoading);
    
    divSearchBox.className = "ajaxWebSearchBox";
    divSearchBox.appendChild(divHeading);
    divSearchBox.appendChild(divResultsPane);
    
    document.body.appendChild(divSearchBox);
    
    this.position(e, divSearchBox);
    
    return divSearchBox;
};

The way the msnWebSearch object is set up, divSearchBox must be returned to its caller for other operations. The position() method, as you may have guessed, positions the search box. It accepts two arguments: the event object passed to drawResultBox() and the divSearchBox element:

msnWebSearch.position = function (e, divSearchBox) {
    var x = e.clientX + document.documentElement.scrollLeft;
    var y = e.clientY + document.documentElement.scrollTop;
	divSearchBox.style.left = x + "px";
    divSearchBox.style.top = y + "px";
};

The first two lines get the left and top positions to place the search results box. Two pieces of information are required to perform this operation. First is the x and y coordinates of the mouse. This information is stored in the clientX and clientY properties.

These coordinates, however, are insufficient to properly position the results box because the clientX and clientY properties return the mouse position in relation to the client area in the browser window, not the actual coordinates in the page. To account for this, use the scrollLeft and scrollTop properties of the document element. With the final coordinates calculated, you can finally position the box where the user clicked the mouse.

Displaying the Results

The populateResults() method populates the result pane with the search results. It accepts two arguments: the element to contain the results and an XParser object (XParser is a JavaScript-based RSS reader freely available for download from www.wdonline.com/javascript/xparser/):

msnWebSearch.populateResults = function (divResultsPane,oParser) {
    var oFragment = document.createDocumentFragment();
    
    divResultsPane.removeChild(divResultsPane.firstChild);

This method generates <a/> elements programmatically with DOM methods, so these elements will be appended to a document fragment created in the first line. The next line removes the loading <div/> element appended in drawResultBox().

The next step is to create the links:

for (var i = 0; i < oParser.items.length; i++) {
    var oItem = oParser.items[i];
        
    var aResultLink = document.createElement("a");
    aResultLink.href = oItem.link.value;
    aResultLink.className = "ajaxWebSearchLink";
    aResultLink.target = "_new";
    aResultLink.appendChild(document.createTextNode(oItem.title.value));
        
    oFragment.appendChild(aResultLink);
}

This code cycles through the items of the feed and generates links from the data and appends the <a/> element to the document fragment.

When the loop exits, the document fragment is appended to divResultsPane to display the search results:

divResultsPane.appendChild(oFragment);