another newbie question - onblur / focus

  • Thread starter please-answer-here
  • Start date
P

please-answer-here

What is wrong with this code?

When I only assign the onblur call to one of the input fields everythings
work, but when I as belove use it on both fields I'll get an endless loop
with the alert messages repeating/replacing each other. I'll guess that the
problem/error must be somewhere in the focus expression but where is it?

******************* code ******************
<html>
<head>
<title>Test1</title>

<script>
function needed(fieldid) {
var form = document.form1;
if (fieldid.value.length == 0) {
alert('Field must not be empty '+ fieldid.name);
form.elements[fieldid.name].focus();
}
}
</script>

</head>
<body>
<form name="form1" action="cgi.asp" method="Post">
<input name="field1" type="text" onblur="needed(this) ">
<input name="field2" type="text" onblur="needed(this) ">
<input type="submit" name="sendit" value="push me">
</form>
</body>
</html>
****************** code ******************
 
M

Martin Honnen

please-answer-here said:
What is wrong with this code?

When I only assign the onblur call to one of the input fields everythings
work, but when I as belove use it on both fields I'll get an endless loop
with the alert messages repeating/replacing each other. I'll guess that the
problem/error must be somewhere in the focus expression but where is it?

It is well-known that using validation code in onblur handlers that
calls alert can trigger an endless loop of focus/blur events and thus
you should not use that. If you want to validate use the onsubmit
handler of the <form> element or if you really see a need to validate
each control after the user has input something then use the onchange
handler.
 
R

Richard Cornford

please-answer-here wrote:
When I only assign the onblur call to one of the input
fields everythings work, but when I as belove use it on
both fields I'll get an endless loop with the alert
messages repeating/replacing each other. I'll guess that
the problem/error must be somewhere in the focus expression
but where is it?

In the long run validating your HTML will save you many headaches while
trying to script the resulting DOM. For valid HTML 4 a SCRIPT element
requires a TYPE attribute.
function needed(fieldid) {
var form = document.form1;

Using the 'shortcut' property accessor - document.form1 -, while
practical and generally successful in HTML DOM implementations, is a bad
habit. The shortcuts are not necessarily available in XHTML DOMs, and
are often taken as implying that all sorts of non-form elements will be
available as named properties of the - document - object, while that
type of shortcut is quite inconstantly implemented.

Given a need to reference a form in a document by name or ID the W3C
HTML DOM standardised/formalised - document.forms - collection is the
place to make such a reference (not the document itself).

As the 'fieldid' parameter contains a reference to a form control a
reference to a containing form object is available as a property of the
form control called 'form' (I.E.:- var form = fieldid.form; -). This
allows the form object to be referenced anonymously, and so the writing
of more general code.
if (fieldid.value.length == 0) {
alert('Field must not be empty '+ fieldid.name);
form.elements[fieldid.name].focus();

Think about what this line of code is doing. You are passed a reference
to the form control as the misnamed 'fieldid' parameter (misnamed
because an ID would be expected to be a string value not an object
reference). You then read the - name - properly of the object referred
to by - fieldid - and use that name value to look-up a reference to a
form control in the form's - elements - collection. If that operation is
successful (as calling a focus method on the result must
(optimistically) assume) the result would be a form control with a -
name - property that corresponds with the - name - property of the form
control passed as a parameter. That is; the result of -
form.elements[fieldid.name] - must be a reference to the _same_ form
control that - fieldid - refers to (unless multiple controls share the
same name, in which case the result of - form.elements[fieldid.name] -
is a collection and the script errors when the collection's
non-existent - focus - method is called).
<input name="field1" type="text" onblur="needed(this) ">
<snip>

A blur event is fired when another element gains focus (or it leave the
document entirely). even when an onblur handler tries to focus another
element the element to which focus was being transferred, to trigger the
initial blur event, will be focused, and so the scripted transfer of
focus will trigger an onblur handler in that second element. Validating
onblur is strongly discouraged because it has a strong tendency to
produce this type of looping.

Richard.
 
P

please-answer-here

Martin said:
It is well-known that using validation code in onblur handlers that
calls alert can trigger an endless loop of focus/blur events and thus
you should not use that. If you want to validate use the onsubmit
handler of the <form> element or if you really see a need to validate
each control after the user has input something then use the onchange
handler.

Thanks for the information which for me as a newbie wasn't "well-known". If
I somehow want's to hold on to the logic which is that the user should be
informed on the error when leaving the field is there any options at all.
The onchange event I'll guess would not not trigger when leaving an
initially empty field.
 
P

please-answer-here

Richard said:
please-answer-here wrote: [snip]

As the 'fieldid' parameter contains a reference to a form control a
reference to a containing form object is available as a property of
the form control called 'form' (I.E.:- var form = fieldid.form; -).
This allows the form object to be referenced anonymously, and so the
writing of more general code.
if (fieldid.value.length == 0) {
alert('Field must not be empty '+ fieldid.name);
form.elements[fieldid.name].focus();

Think about what this line of code is doing. You are passed a
reference to the form control as the misnamed 'fieldid' parameter
(misnamed because an ID would be expected to be a string value not an
object reference).

If I understand you right it is wrong to use fieldid.name in the
elements.[] reference. But how can I pas it as a string?

You then read the - name - properly of the object
referred to by - fieldid - and use that name value to look-up a
reference to a form control in the form's - elements - collection. If
that operation is successful (as calling a focus method on the result
must (optimistically) assume) the result would be a form control
with a - name - property that corresponds with the - name - property
of the form control passed as a parameter. That is; the result of -
form.elements[fieldid.name] - must be a reference to the _same_ form
control that - fieldid - refers to (unless multiple controls share the
same name, in which case the result of - form.elements[fieldid.name] -
is a collection and the script errors when the collection's
non-existent - focus - method is called).

You then read the - name - properly of the object referred to by - fieldid -
and use that name value to look-up a
reference to a form control in the form's - elements - collection. If that
operation is successful the result would be a form control
with a - name - property that corresponds with the - name - property of the
form control passed as a parameter.

I've read the above statement several times without fully grasping the
essense. Could you by chance explain this in a another way which makes
better understanding to a newbie in javascript/html .

<snip>

A blur event is fired when another element gains focus (or it leave
the document entirely). even when an onblur handler tries to focus
another element the element to which focus was being transferred, to
trigger the initial blur event, will be focused, and so the scripted
transfer of focus will trigger an onblur handler in that second
element. Validating onblur is strongly discouraged because it has a
strong tendency to produce this type of looping.

Thanks for this very deep and informative information.Nice to see things
explained a litte "deeper" than those "intro/teach yourself" etc. books I've
stumpled upon.

So if I wan't to test the validity/nonemptiness of input fields before
submitting the entire form do I have any options at all.
 
M

Martin Honnen

please-answer-here said:
If
I somehow want's to hold on to the logic which is that the user should be
informed on the error when leaving the field is there any options at all.
The onchange event I'll guess would not not trigger when leaving an
initially empty field.

It is correct that onchange is not fired when the user enters and leaves
a field that is empty.
If you insist on using onblur then you can of course in modern browsers
dynamically create and insert the validation error message directly in
the HTML document itself, next to the field, here is a simple example to
outline how that could work:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>inline validation messages</title>
<style type="text/css">
span.validationError {
color: red;
font-weight: bold;
}
</style>
<script type="text/javascript">
function setInnerText (element, text) {
if (typeof element.innerText != 'undefined') {
element.innerText = text;
}
else if (element.hasChildNodes && element.appendChild) {
while (element.hasChildNodes()) {
element.removeChild(element.lastChild);
}
element.appendChild(document.createTextNode(text));
}
}

function createErrorMessage (control, message) {
var errorElement = control.errorElement;
if (!errorElement && document.createElement) {
errorElement = document.createElement('span');
errorElement.className = 'validationError';
control.parentNode.appendChild(errorElement, control.nextSibling);
control.errorElement = errorElement;
}
if (errorElement) {
setInnerText(errorElement, message);
}
}

function checkError (control) {
if (control.value == '') {
createErrorMessage(control, 'You need to enter a value here.');
}
}

function clearError (control) {
if (control.errorElement) {
setInnerText(control.errorElement, '');
}
}
</script>
<script type="text/javascript">
function output (tagName, text) {
var element = document.createElement(tagName);
element.appendChild(document.createTextNode(text));
document.body.appendChild(element);
}
</script>
</head>
<body>

<form action="whatever.asp">
<div>
<label>
field 1
<input type="text" name="field1"
onfocus="clearError(this);"
onblur="checkError(this);">
</label>
</div>
<div>
<label>
field 2
<input type="text" name="field2"
onfocus="clearError(this);"
onblur="checkError(this);">
</label>
</div>
<div>
<input type="submit">
</div>
</form>

</body>
</html>
 
M

Michael Winter

Richard Cornford wrote:
[snip]
You are passed a reference to the form control as the misnamed
'fieldid' parameter (misnamed because an ID would be expected to be
a string value not an object reference).

If I understand you right it is wrong to use fieldid.name in the
elements.[] reference.

In that particular sentence, Richard is just referring to the name of
the identifier, fieldid. Identifiers should be meaningful and help make
code easier to understand. It is clear that fieldid doesn't contain the
id of a field, but a reference, therefore field would be more appropriate.
But how can I pas it as a string?

You don't need to, as the next part of Richard's post said.

[snipped somewhat obscure explanation :p]
I've read the above statement several times without fully grasping
the essense. Could you by chance explain this in a another way which
makes better understanding to a newbie in javascript/html .

The reason you were trying:

form.elements[fieldid.name]

was to get a reference to a field so you could call its focus method.
However, fieldid /is/ a reference to that field, so it's a waste of
time. Instead, use:

if(field.focus) {
field.focus();
}

assuming the identifier change fieldid->field suggested above.

[snip]
So if I wan't to test the validity/nonemptiness of input fields
before submitting the entire form do I have any options at all.

If you want to validate form controls prior to the submit event, you can
use the change event. This is preferable not only because it can't form
never ending loops, but that it only fires when a value is changed so
users won't be bugged constantly.

Mike
 
P

please-answer-here

Michael said:
Richard Cornford wrote:

[snip]


In that particular sentence, Richard is just referring to the name of
the identifier, fieldid. Identifiers should be meaningful and help
make code easier to understand. It is clear that fieldid doesn't
contain the id of a field, but a reference, therefore field would be
more appropriate.

Point taken. Actually the "error" is mainly due to a quick translation from
danish.
The reason you were trying:

form.elements[fieldid.name]

was to get a reference to a field so you could call its focus method.
However, fieldid /is/ a reference to that field, so it's a waste of
time. Instead, use:

if(field.focus) {
field.focus();
}

Oooh that makes sense
If you want to validate form controls prior to the submit event, you
can use the change event. This is preferable not only because it
can't form never ending loops, but that it only fires when a value is
changed so users won't be bugged constantly.

Point taken, but still leaves me with the problem about how to test for
whether a user left an initially blank field blank. I will take a deeper
look at Martin Honnens suggestions if its the only way to do it.
 
M

Michael Winter

On 04/06/2005 17:08, please-answer-here wrote:

[MW: Using the change event]
Point taken, but still leaves me with the problem about how to test for
whether a user left an initially blank field blank. [...]

There's no reason why you can't combine per-field validation with
validation of the entire form. With the latter, you can perform a sanity
check for all input.

Of course, if you're validating server-side too (and I hope you are),
then client-side validation is just a convenience and not something to
get too worried about.

Mike
 
R

RobG

please-answer-here said:
Michael said:
Richard Cornford wrote:

[snip]


In that particular sentence, Richard is just referring to the name of
the identifier, fieldid. Identifiers should be meaningful and help
make code easier to understand. It is clear that fieldid doesn't
contain the id of a field, but a reference, therefore field would be
more appropriate.


Point taken. Actually the "error" is mainly due to a quick translation from
danish.
The reason you were trying:

form.elements[fieldid.name]

was to get a reference to a field so you could call its focus method.
However, fieldid /is/ a reference to that field, so it's a waste of
time. Instead, use:

if(field.focus) {
field.focus();
}


Oooh that makes sense

If you want to validate form controls prior to the submit event, you
can use the change event. This is preferable not only because it
can't form never ending loops, but that it only fires when a value is
changed so users won't be bugged constantly.


Point taken, but still leaves me with the problem about how to test for
whether a user left an initially blank field blank. I will take a deeper
look at Martin Honnens suggestions if its the only way to do it.

Don't get too hung up on validation. If the user never puts focus on
the empty field, onblur wont run either.

A user may not want to fill in that field just yet, or may wish to
leave it for a moment to do something else. Constant alerts annoy the
hell out of people, the form only needs to be valid when submitted, not
before.

Offer good on-screen assistance so users know what's needed, put
warnings in the HTML rather than alerts and do a final validation on
submit - remembering that none of your client-side validation will have
run for users with JavaScript disabled (or a JS-less UA).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top