Chapter 6: Beginning JavaScript
Creating 'Encoded' Name & Value Pairs
Passing data from one form to another
Addressing Form Field Validation with Regular Expressions and JavaScript 1.2
You are here: irt.org | Articles | JavaScript | Form | Controlling Data Entry Using Form Fields [ previous next ]
Published on: Sunday 17th October 1999 By: Martin Webb
How can you automatically jump to another field once the current field has been competed. For example, when entering a telephone number into separate one character sized form fields?
Why you might want to do this is not important. How to do it, caused a fair bit of head scratching here at irt.org when asked to raise to the challenge. The rest of this article explains the reasons why it isn't as easy as it might first appear, and shows a fully working example at the end.
First, a simple form with three fields, all one character in length:
<form name="myForm1"> <input type="text" maxlength="1" name="f1" size="1"> <input type="text" maxlength="1" name="f2" size="1"> <input type="text" maxlength="1" name="f3" size="1"> </form>
Which results in a form looking like:
Each field is one character wide (size="1") and accepts a maximum of one character (maxlength="1"). What would be nice, is if once the field has been completed for the cursor to be automatically positioned into the next field - so as to allow the user to continue typing uninterrupted.
The following code, is the first attempt at achieving this. It use the onKeyUp event handler to invoke the advance() function, which attempts to check the value of the current form field (this), and if the length of its value property is one character, then it changes the focus of the text caret to the next form field:
<script language="JavaScript"><!-- function advance(currentField,nextField) { if (currentField.value.length == 1) document.myForm[nextField].focus(); } //--></script> <form name="myForm2"> <input type="text" maxlength="1" name="f1" size="1" onKeyUp="advance(this,'f2')"> <input type="text" maxlength="1" name="f2" size="1" onKeyUp="advance(this,'f3')"> <input type="text" maxlength="1" name="f3" size="1"> </form>
As you'll find out, the following form which uses the above code doesn't work as expected:
It only works if, and only if, the focus is manually changed (by the user) from the original text field to some other object, and the user then goes back to attempt to change the original form field - in which case, although the field is not altered another onKeyUp event is invoked, which then cause the focus to change.
The next few examples attempt to explain this.
In the nearly all the remaining examples the HTML for the form remains unchanged, so we just concentrate on the JavaScript code.
When something doesn;t work as expected, its time to debug your code. And as most JavaScript coders know, the alert() method is your best friend. The following code includes an alert() method to give us an idea of what is going on within the advance() function:
<script language="JavaScript"><!-- function advance(currentField,nextField) { alert("value: " + currentField.value + " Length: " + currentField.value.length); if (currentField.value.length == 1) document.myForm[nextField].focus(); } //--></script>
When you test the following code, you'll see the alert message popup - and you'll possibly be surprised to find that, although you entered a character within the form field, the alert message shows the value as emtpy, and the value length as zero:
The fundamental lesson to be learnt here, is that the value property of a form field is not altered until after the form field has lost the focus. Therefore you cannot access the value of the form field whilst the user is still typing text into the form field. The value is the value of the form field before the user started typing.
One other to point to bear in mind is that on some systems the alert message acts as a non modal dialogue, i.e. the JavaScript code continues to execute even though the alert message is visible. The following will demonstrate this on those systems that are affected:
<script language="JavaScript"><!-- function advance(currentField,nextField) { alert("value: " + currentField.value + " Length: " + currentField.value.length); alert("value: " + currentField.value + " Length: " + currentField.value.length); if (currentField.value.length == 1) document.myForm[nextField].focus(); } //--></script>
Note, how neither of the alerts show an initial value. To actually cause the form field to lose focus and hence update its value property, you need to click or press enter on one of the two alert boxes. Only after this has happened will any check on the form field detect the new value, its new length and then focus on the next form field.
The prompt dialogue message on the other hand is a modal dialogue - processing is halted whils the dialogue is being displayed, and can only continue after the dialogue has been closed:
<script language="JavaScript"><!-- function advance(currentField,nextField) { prompt("Debug:","value: " + currentField.value + " Length: " + currentField.value.length); if (currentField.value.length == 1) document.myForm[nextField].focus(); } //--></script>
To close the prompt dialogue requires the user to click one of the dialogue buttons. Note how after this happens the focus changes to the next form field.
The following example uses two prompt messages one after to another to show how clicking on one prompt dialogue causes the form fields value property to change to the character just typed in:
<script language="JavaScript"><!-- function advance(currentField,nextField) { prompt("Debug:","value: " + currentField.value + " Length: " + currentField.value.length); prompt("Debug:","value: " + currentField.value + " Length: " + currentField.value.length); if (currentField.value.length == 1) document.myForm[nextField].focus(); } //--></script>
Notice how the value property of the form field is empty in the first prompt message, but not in the second.
This is because (as I mentioned before) the value property of the form field is NOT set until after the form field losses the focus. The prompt message has to be acknowledged before you can carry on with the form, this explicitly causes the form field to lose focus, as you either have to click the ok or cancel button to get rid of the prompt message.
However - depending on what system you are using, an alert message doesn't have the same effect as a modal prompt dialogue box. First the alert message is not a modal dialogue box, it is a non modal dialogue box. The code continues whilst the alert box is being generated on the screen, therefore clicking on an alert message may not have the same effect.
The trick is to cause the form field to lose focus (automatically and without user intervention) before checking its value.
The following example which attempts to lose the focus within the current field, by using the blur() method doesn't quite do it:
<script language="JavaScript"><!-- function advance(currentField,nextField) { currentField.blur(); if (currentField.value.length == 1) document.myForm[nextField].focus(); } //--></script>
The blur() method doesn't appear to have any effect
The form field either doesn't quite lose focus before the test, or perhaps the way that JavaScript works is to only actually change the focus when the currently executing script has returned control back to the browser.
The following example, which attempts to use the focus() to give focus to another form field also doesn't quite do it:
<script language="JavaScript"><!-- function advance(currentField,nextField) { document.myForm['f3'].focus(); if (currentField.value.length == 1) document.myForm[nextField].focus(); } //--></script>
The previous example changes the focus to the third field, but the request to change to the next field doesn't happen, probably for the same reasons as in the previous example.
The following does it correctly:
<script language="JavaScript"><!-- var currentField, nextField; function advance(c,n) { currentField = c, nextField = n; document.myForm['f3'].focus(); setTimeout('effect()',1); } function effect() { if (currentField.value.length == 1) document.myForm[nextField].focus(); } //--></script>
It causes the form field to lose focus by focusing on another form field, it then stores the passed references/values to the current field (c) and the next field (n) in global variables (currentField, nextField) and then sets a timer running to trigger in one milliseconds time. The currently running script then ends, and a millisecond later the effect() function is triggered to check the value and length of the orginal form field.
However, if the user wants to go back and alter one of the previous entries, then pressing the delete key has the same effect as entering a character, the focus changes to the temporary form field, but because the original form fields value length is zero (it was deleted remember?) then it leaves the cursor in the temporary form field. We actually need to test for this and give focus to the original form field to allow the user to first delete the entry and then carry on by entering the new value.
the follwoign example includes this as part of the else statement, and shows a enlarged example demonstrating eleven form fields suitable for capturing a telephone number:
<script language="JavaScript"><!-- var currentField, nextField; function advance(c,n) { currentField = c, nextField = n; document.myForm['f11'].focus(); setTimeout('effect()',1); } function effect() { if (currentField.value.length == 1) document.myForm[nextField].focus(); else currentField.focus(); } //--></script> <form name="myForm"> <input type="text" maxlength="1" name="f1" size="1" onKeyUp="advance(this,'f2')"> <input type="text" maxlength="1" name="f2" size="1" onKeyUp="advance(this,'f3')"> <input type="text" maxlength="1" name="f3" size="1" onKeyUp="advance(this,'f4')"> <input type="text" maxlength="1" name="f4" size="1" onKeyUp="advance(this,'f5')"> <input type="text" maxlength="1" name="f5" size="1" onKeyUp="advance(this,'f6')"> <input type="text" maxlength="1" name="f6" size="1" onKeyUp="advance(this,'f7')"> <input type="text" maxlength="1" name="f7" size="1" onKeyUp="advance(this,'f8')"> <input type="text" maxlength="1" name="f8" size="1" onKeyUp="advance(this,'f9')"> <input type="text" maxlength="1" name="f9" size="1" onKeyUp="advance(this,'f10')"> <input type="text" maxlength="1" name="f10" size="1" onKeyUp="advance(this,'f11')"> <input type="text" maxlength="1" name="f11" size="1"> </form>
Chapter 6: Beginning JavaScript
Creating 'Encoded' Name & Value Pairs
Passing data from one form to another
Addressing Form Field Validation with Regular Expressions and JavaScript 1.2