3.5 Example: A Support Form 67
The advantage of the loop is that we can now add any number of textarea ele-
ments, and as long as they have a meter element, they will be updated automati-
cally. To achieve this, we need to resort to a DOM trick: The code printed in bold
in the preceding listing accesses the DOM function nextSibling, a reference to
the next element. Let’s revisit the HTML code for the text field and the status
bar to make things clearer. The textarea element is enclosed by a label element
followed by the desired meter element. To get from the textarea element to the
meter element, we use the text field’s labels property. This is a NodeList array,
and we are interested in the first element (with the index 0 ), because the follow-
ing element (the nextSibling) is the meter element.
If you look closely, the procedure is not as complicated as it at first looks, but it
has a few snags. If there is a stray whitespace or line break that sneaks in between
the enclosing label element and the meter element, then our status display no
longer works. The nextSibling then becomes a text element, and we can no lon-
ger reach the meter element in the for loop.
Next we want to program the progress display at the end of the form. You prob-
ably guessed that it is a progress element; More interesting is how we can el-
egantly express updating this element in JavaScript. First, here is the HTML code
for the element:
We assign to the progress element an id, a starting value of 0 (value), and a nega-
tive tabindex, which means that the element is never accessed with the Tab key.
The JavaScript function updateProgress() updates the progress element:
function updateProgress() {
var req = document.querySelectorAll(":required");
count = 0;
for(var i=0; i<req.length; i++) {
if (req[i].value != '') {
count++;
}
}
var pb = document.getElementById("formProgress");
pb.max = req.length;
pb.value = count;
}
Because the progress bar is only supposed to refer to the elements that are ab-
solutely required, we pass the character string :required to the function query-
SelectorAll(). The result is a NodeList containing only elements that have the
required attribute. A loop is then run over these elements, checking whether the