Article
Well-Behaved DHTML: A Case Study
The solution, of course, is to give a special class to the labels we want to behave dynamically:
<style type=”text/css”>
label.dynamic {
display:none;
}
</style>
The second task essentially requires that we loop over all the label elements on the page, check to see whether they have the correct class, and if they do, add event handlers to their associated field. We should also save a copy of the label text in a property of the field for easy access, and initialize the label display while we’re here.
This requires some knowledge of the document object model. If you’re rusty on the details, or never took the time to learn, you can brush up at the W3C. Browser vendors often have good resources as well (e.g. Microsoft, and Mozilla), although these are obviously skewed toward their own implementations.
In a perfect world, once we learned how the DOM works, we could use the following code to perform our task. It uses getElementsByTagName the getElementById methods, as well as the className property. Each of these is defined in DOM Level 1 – HTML.
This code also uses the addEventListener method from DOM Level 2 Events.
n setupLabels() {
// get all the labels on the entire page
var objLabels = document.getElementsByTagName("LABEL");
var objField;
for (var i = 0; i < objLabels.length; i++) {
// if the label is supposed to be dynamic...
if ("dynamicLabel" == objLabels[i].className) {
// get the field associated with it
objField = document.getElementById(objLabels[i].htmlFor);
// add event handlers to the onfocus and onblur events
objField.addEventListener(“focus”, focusDynamicLabel, false);
objField.addEventListener(“blur”, blurDynamicLabel, false);
// save a copy of the label text
objField._labelText = objLabels[i].firstChild.nodeValue;
// initialize the display of the label
objField.value = objField._labelText;
}
}
}
However, this code won’t work for IE/windows because it isn’t fully DOM-compliant; it doesn’t support the DOM Level 2 Events Module. Instead, it supports a proprietary interface that does the same thing. As IE/windows has such a huge user base -- and one we’d like to have see our effect -- we add a small hack to our script to accommodate its different object model (note the changed lines are bold):
function setupLabels() {
// get all the labels on the entire page
var objLabels = document.getElementsByTagName("LABEL");
var objField;
for (var i = 0; i < objLabels.length; i++) {
// if the label is supposed to be dynamic...
if ("dynamicLabel" == objLabels[i].className) {
// get the field associated with it
objField = document.getElementById(objLabels[i].htmlFor);
// add event handlers to the onfocus and onblur events
addEvent(objField, "focus", focusDynamicLabel);
addEvent(objField, "blur", blurDynamicLabel);
// save a copy of the label text
objField._labelText = objLabels[i].firstChild.nodeValue;
// initialize the display of the label
objField.value = objField._labelText;
}
}
}
function addEvent(objObject, strEventName, fnHandler) {
// DOM-compliant way to add an event listener
if (objObject.addEventListener)
objObject.addEventListener(strEventName, fnHandler, false);
// IE/windows way to add an event listener
else if (objObject.attachEvent)
objObject.attachEvent("on" + strEventName, fnHandler);
}
We can make this script run once the page is loaded by attaching to the window’s onload event with the same utility function.
addEvent(window, "load", setupLabels);
Now all we have to do is implement focusDynamicLabel and blurDynamicLabel. This is easy -- it’s just like the original code from our first dynamic label script. The only difference is that it should be generalized so the same function works for each dynamic label on the page.
In a fully DOM-compliant browser, we could use the target property of the event object (Also defined in DOM Level 2 Events) to obtain a reference to the element that fired the event, and manipulate it:
function focusDynamicLabel(event) {
// get the form field that fired this event
var elm = event.target;
// if it is currently displaying the label...
if (elm._labelText == elm.value) {
// ... turn it off
elm.value = "";
}
}
function blurDynamicLabel(event) {
// get the form field that fired this event
var elm = event.target;
// if it’s empty...
if ("" == elm.value) {
// ... display the label text
elm.value = elm._labelText;
}
}
But once again, IE/windows implements this functionality slightly differently, using the property srcElement instead of the standardized target, and making the event object available through window.event instead of the standardized way of passing it implicitly to event handler functions.
We’ll need another small hack and helper function:
function focusDynamicLabel(event) {
// get the form field that fired this event
var elm = getEventSrc(event);
// if it is currently displaying the label...
if (elm._labelText == elm.value) {
// ... turn it off
elm.value = "";
}
}
function blurDynamicLabel(event) {
// get the form field that fired this event
var elm = getEventSrc(event);
// if it’s empty...
if ("" == elm.value) {
// ... display the label text
elm.value = elm._labelText;
}
}
function getEventSrc(e) {
// get a reference to the IE/windows event object
if (!e) e = window.event;
// DOM-compliant name of event source property
if (e.target)
return e. target;
// IE/windows name of event source property
else if (e.srcElement)
return e.srcElement;
}
Example C shows our work so far.