These new event handlers, onKeyDown, onKeyPress, and onKeyUp, can be used to trap keyboard events whenever a text box has focus. In this article, we'll look at how you can use one of these new event handlers, onKeyUp, to capture individual characters that the user types and then use those characters to find text strings on a Web page.
The new keyboard event handlers
The onKeyDown event handler fires when the user presses the key far enough to make contact, while the onKeyUp handler fires when electrical contact with the key breaks. The onKeyPress event handler fires when there has been one complete combination of KeyDown and KeyUp events.
Once you trap a keyboard event, you also need to get the character value of the key that was pressed. Fortunately, the character value of a key is a property of the keyboard event object that's created every time an event occurs. Once the key value is captured, however, it also needs to be converted from the way it's represented in the system (its character code) to an alphanumeric character that we recognize. We'll show you how to do all that in this article.
Welcome to the Monroe County Mall
The example we've worked up to illustrate the onKeyup event handler is a store directory for the fictitious Monroe County Mall. Monroe County Mall's directory page is displayed in Figure A.
Figure A: You can find a store on the Monroe County Mall's directory page by typing just a partial name in the text box.
The purpose of the page is to allow a user to type even the partial name of a store, and the page will find a match among the list of stores displayed. The name of the store that was found is highlighted by having an arrow appear next to the store name.
In Figure B, the user has typed in one character, "C", and the arrow points to the store Chairs for Everyone.
Figure B: Typing just one character finds the first store with that character in its name.
Then, in the Figure C, the user has typed in a second character, "a", and now the arrow points to the store named Captain Ahab's Pizza. As the user continues to type, the matching is refined until the store the user wants is highlighted.
Figure C: Typing a second character refines the search until the store the user is looking for is found.
Monroe County Mall's directory page uses frames, and Listing A contains the frame definition for the page.
Listing B shows the code for the list of stores that appears in the right-hand frame of our page, which we've named stores. Notice that each of the items on the list has been given a name. We'll use that name later to insert the arrow that highlights the store name.
Listing A: Frame definition file for the Monroe County Mall directory page
<HTML>
<FRAMESET cols = "250, *" >
<FRAME name = "message" src = "message2.htm">
<FRAME name = "stores" src = "stores2.htm">
</FRAMESET>
</HTML>
Listing B: Code for the stores frame<HTML>
<HEAD>
<TITLE> Monroe County Mall store listing</TITLE>
<STYLE>
LI {list-style:none}
</STYLE>
</HEAD>
<BODY >
<UL>
<LI name = "Bonmot" > Bonmot's </LI>
<LI name = "Chairs" > Chairs for Everyone </LI>
<LI name = "Captain" > Captain Ahab's Pizza </LI>
<LI name = "Donuts" > Donuts by Dolores </LI>
<LI name = "Everything"> Everything's A Dollar
Ninety-Nine </LI>
<LI name = "Gilda's" > Gilda's</LI>
<LI name = "Greasy" >The Greasy Spoon </LI>
<LI name = "Harry"> Harry's House of
Haberdashery </LI>
<LI name = "KiddleDoodle" > KiddleDoodle</LI>
<LI name = "Sixties" > The Sixties Store </LI>
<LI name = "Tilda" > Tables Settings by Tilda </LI>
<LI name = "Victoria" > Victoria's Broom
Closet </LI>
</UL>
</BODY>
</HTML>
Finding a store at the Mall
The file that appears in the left-hand frame on our page, which we've named message, contains the code that actually does all the work. The code for this file appears in Listing C. If you start by looking at the BODY code, you'll see that it contains a text box (called inbox) and two buttons. When the user releases a key after typing a character into the text box, the event is captured by the onKeyUp handler, which calls the findstore function, passing it the event object that was trapped.
Listing C: Code for the message frame
<HTML>
<HEAD>
<TITLE> index page</TITLE>
<STYLE>
IMG {float:left;height:10;width:10}
P {font-size: 14; font-family: palatino;
font-weight: 400; text-align: center}
P.sell {font-size: 20; font-family: arial;
font-weight: bold}
</STYLE>
<SCRIPT language = "JScript">
var storename = new String;
var newstore = new String;
var first = true;
var myelement;
var mystring = new String;
var mytext = new String;
function findstore(e) {
var bodyText = parent.stores.document.
body.createTextRange();
var charCode = String.fromCharCode(e.keyCode);
if ((charCode >= "a" && charCode <= "z") ||
(charCode >= "A" && charCode <= "Z" )) {
if (bodyText.findText(inbox.value)) {
//Remove arrow pointing to store previously
//found by replacing its original contents
if ( !first)
myelement.innerText = mytext;
myelement = bodyText.parentElement();
mytext = myelement.innerText;
myelement.innerHTML = "<img src =
'R_arrow.gif' align = left>" + mytext;
first = false;
}
}
}
function showstores() {
parent.stores.document.location = "stores2.htm";
}
function showmap() {
if (inbox.value != "")
parent.stores.document.location = myelement.name
+ ".htm";
//Empty the text box
inbox.value = "";
}
</SCRIPT>
</HEAD>
<BODY onload = "inbox.value = "">
<P class = sell>
Welcome to the Monroe County Mall.
<BR>
We sell EVERYTHING!
<P>
To find the store from our listing, begin
entering the name of the store
you are looking for in the
text box. Don't worry if you don't know the full
name - even a partial name will do! <BR>
<BR>
<INPUT name = "inbox" type = "text"
onkeyup="findstore(event)" >
<BR>
<BR>
<INPUT name = "map" type = "button" value =
"Mall Map" onclick ="showmap()" >
<BR>
<INPUT name = "map" type = "button" value =
"Store Listing" onclick ="showstores()" >
</BODY>
</HTML>
The first thing findstore does is create a textRange object, named bodyText,
over the BODY of the document in the stores frame; that is, the document
displaying our store listing. Then the statement
var charCode =
String.fromCharCode(e.keyCode);
accomplishes several things. The keyCode property of e, the event that was
passed to the function, is sent to the String method fromCharCode. This
converts the character code representation of our character to an alphanumeric
character, which is then assigned to the variable charCode. The if statement
if ((charCode >= "a" && charCode <= "z") ||
(charCode >= "A" && charCode <= "Z" ))
checks to make sure that the character is a letter, and if it is, we process
the rest of the statements in the if block. The statement
if (bodyText.findText(inbox.value)) {
is
responsible for finding the store name that most closely matches the partial
string currently in the text box. Since bodyText points to all of the text in
the document containing our store listing, it can use the textRange method
findtext to find
matching text in that document. If matching text is found, bodyText now points
to the text (that is, some part of a store name within an LI element) that it
found.Your store here
The last tricky little piece of code in this function is responsible for placing the arrow next to the store name that was found. All we currently have is the partial store name within an LI element that matches the string in the text box. What we want is the entire text string so we can then add a graphic to it. Here are the statements that accomplish that:
myelement = bodyText.parentElement();
mytext = myelement.innerText;
myelement.innerHTML = "<img src =
'R_arrow.gif' align = left>" + mytext;
First, myelement is assigned the parent element of the text we've found, which
its LI element. Then, we get the entire text in that LI element using the
innerText property (remember, it's read/write so we can get its value as well
as change its value) and assign it to mytext. Finally, we assign a new value
for the LI element using the innerHTML property, adding the IMG tag with our
arrow image to the original text we copied into mytext.Who's on first?
The only thing we haven't explained in this function is the Boolean variable first, which we declared as a global in the beginning of our script. We need that Boolean variable because as the user moves from store name to store name, we want to display only one arrow. The first time we assign an arrow to an element, we don't need to worry, but after the first time, we need to strip the arrow off of the element we previously found by replacing its original text. Since the original text has been saved in the mytext variable, we can put it back with the statement:
if ( !first)
myelement.innerText = mytext;
Using the variable first in this way is an excellent illustration of the power
of Boolean variables in your scripts. We'll talk more about Boolean variables
in a future issue of Microsoft Web Builder.
If you need a map...
There are two other functions in Listing C: showstores and showmap. They're simple enough--when the user clicks on the Mall Map button, showmap is called and a map showing the location of the selected store is loaded into the stores frame with the statement
parent.stores.document.location =
myelement.name + ".htm";
This is shown in Figure D. The function showstores simply replaces the
map with the original store listing.Figure D: Clicking on the Mall Map button brings up a map of the Mall, showing the location of the selected store.
Notice that we used the strategy of concatenating the name of the element with ".htm" to get that element's file name.
Conclusion
We touched on quite a few DHTML features as we developed our simple store directory example: the onkeyUp event handler; the textRange's findtext method and parentElement property; the keycode property of the event object; the String method changeCode; and the element properties innerText and innerHTML. We also did a little more dynamic frame loading. If you've developed a project using some of these same features, we'd love to hear about it, and maybe even share it with our readers. Send email to webbuilder@zdjournals.com.
Copyright © 1999, ZD Inc. All rights reserved. ZD Journals and the ZD Journals logo are trademarks of ZD Inc. Reproduction in whole or in part in any form or medium without express written permission of ZD Inc. is prohibited. All other product names and logos are trademarks or registered trademarks of their respective owners.