AJAX In Action [186]
function BuildList(theText){
SetElementPosition(theTextBox);
Set element position
var theMatches = MakeMatches(theText);
Format matches
theMatches = theMatches.join().replace(/\,/gi,"");
if(theMatches.length > 0){
document.getElementById("spanOutput")
.innerHTML = theMatches;
document.getElementById(
Show
"OptionsList_0").className =
results
"spanHighElement";
currentValueSelected = 0;
bNoResults = false;
}
else{
currentValueSelected = -1;
bNoResults = true;
if(theTextBox.obj.showNoMatchMessage)
document.getElementById(
"spanOutput").innerHTML =
Show no
"" + matches theTextBox.obj .noMatchingDataMessage + "
else HideTheBox();
}
}
The function BuildList() in listing 10.13 takes the string the user entered and formats the results. The first thing we need to do is dynamically position the span element directly under the textbox from which the type-ahead is being implemented. To do this, we call the function SetElementPosition() (which we develop Licensed to jonathan zheng The client-side framework 383 in the section “Dynamically setting an element’s position”). After we position the span element, we can start to manipulate the array to find the matches by using the MakeMatches() function (see the section “Using regular expressions”). This function returns an array that contains only the information that matches the user’s input. We are using JavaScript to limit the results on the client rather than requiring the processing to be done on the server like most of the type-ahead applications available online. The MakeMatches() function formats the results and returns them as an array. We then turn this array into a string by using the join method. If the length of the string is greater than 0, then we can display the results in a span by setting its innerHTML property. Then we select the first element in the list and set its className so it is highlighted. If the returned array contains no data, then we display our “no matches” message if the textbox allows it. We make sure that we set the currentSelectedValue to -1 so we know there are no matches. If no message is to be displayed, then we just hide the box. We’ve finished the BuildList() function, so now we have to create all the functions that it calls. The first one we’ll tackle is SetElementPosition(). Dynamically setting an element’s position The input textbox is positioned on the page by the browser's layout engine. When we construct the DHTML drop-down suggest, we want to place it exactly in line with the textbox. One of our most difficult tasks is finding the position of a nonpositioned element, in this case the textbox, so that we can compute the dropdown’s coordinates. A nonpositioned element is one that is relatively set on the page without specifying the absolute left and top positions. If we reference the left and top positions for our textbox, we’ll get an undefined string returned. Therefore, we need to use some JavaScript to determine the position of our element so that our box of choices lines up directly underneath it. In listing 10.14, we are dynamically positioning the span element to line up under our textbox. Listing 10.14 Dynamically finding the position of a nonpositioned element function SetElementPosition(theTextBoxInt){ var selectedPosX = 0; var selectedPosY = 0; var theElement = theTextBoxInt; if (!theElement) return; var theElemHeight = theElement.offsetHeight; var theElemWidth = theElement.offsetWidth; Licensed to jonathan zheng 384 CHAPTER 10 Type-ahead suggest while(theElement != null){ selectedPosX += theElement.offsetLeft; selectedPosY += theElement.offsetTop; theElement = theElement.offsetParent; } xPosElement = document.getElementById("spanOutput"); xPosElement.style.left = selectedPosX; if(theTextBoxInt.obj.matchTextBoxWidth) xPosElement.style.width = theElemWidth; xPosElement.style.top = selectedPosY