faqts : Computers : Programming : Languages : JavaScript : Frames

+ Search
Add Entry AlertManage Folder Edit Entry Add page to http://del.icio.us/
Did You Find This Entry Useful?

43 of 72 people (60%) answered Yes
Recently 7 of 10 people (70%) answered Yes

Entry

Change focus between frames in IE5.0, and validate form (fix "unspecified error")
Submit form in another frame in IE5.0, and still validate fields and use focus (fix "unspecified error)
onchange and onsubmit only being called once or not at all (especially related to frames and IE5.0)

Sep 12th, 2002 06:54
Moe Cazzell,


Assume you have at least two frames:
<frame src="..." name="buttons" ...>
<frame src="..." name="page">

And on the "page" frame you have a form with an onsubmit event
handler and at least one field with a onchange event handler:

<form id="EntryForm" name="EntryForm" ... onsubmit="return OnSubmit();">
<input name="field1" ... onchange="return OnChangeField1();">

And you want a button on the "buttons" page to submit a form on 
the "page" frame, without bypassing nor breaking any field validation 
that occurs in the event handlers.

<button type=button onclick="DoSubmit()">Submit Form</button>

First, let's consider a typical setup for the event handlers on 
the "page" frame, and consider the problems associated with them that 
we need to solve. (Skip to Step 3 to see the onclick event handler)

1) Field onchange Event Handlers: onchange="return OnChangeField1();"

Normally, if you return true here, focus is allowed
to change to another field, but if you return false here
the user is not allowed to leave the field.

You may be tempted to normalize this field or trim white 
space in this field before validating. 

! However, in IE, any change to the field
causes focus to leave the field, as if the return
was true, even if you return false !

Thus, store a local copy of any trimmed/normalized version, 
then validate this local copy first, and only put it in the field 
if validation succeeds.

function OnChangeField1() {
    var s=trim(EntryForm.field1.value, ' '); // my trim function
    if (!ValidField1(s)) { // my validation function
        alert("Enter valid data"); // field is not valid
        EntryForm.field1.value.focus();
        EntryForm.field1.value.select(); // highlight field
        return false; // don't allow focus change
    }
    // field is valid, store trimmed/normalized version, if different
    if (s!=EntryForm.field1.value) EntryForm.field1.value=s;
    return true; // allow focus change
}

In versions of IE after IE5.0, clicking in another frame (or any change 
of focus) causes the onchange event handler to be called for the form 
control which currently has focus, thus allowing individual form fields 
to be validated.

But in IE5.0, clicking a button in another frame does *not* cause the 
onchange event handler to be called.

See the "buttons" frame onclick event handler for the submit button.

2) Form onsubmit Event Handler: onsubmit="return OnSubmit();"

If your form starts empty, but an empty field is not valid,
then it may be likely that the submit button is pressed without
ever having the onchange called for that field. So repeat all field 
validation in the onsubmit handler. However, you shouldn't need to
trim the field, as it should be either valid or empty or set to
a default value (that you control).

function OnSubmit() {
    ....
    if (!ValidField1(EntryForm.field1.value)) { 
        alert("Enter valid data"); // some field is not valid
        EntryForm.field1.value.focus();
        EntryForm.field1.value.select(); // highlight field
        return false; // don't allow form action
    }
    ...

    // all fields are valid
    return true; // allow form action
}

Normally, if your OnSubmit returns true, the form action proceeds,
but if it returns false, no action occurs.

! However, in all versions of IE, merely calling the submit() method 
of the form does *not* call the onsubmit event handler !

Your submit button in the "buttons" frame will need to call 
the onsubmit handler manually to make sure that the fields are 
all validated.

3) Button onclick Event Handler: onclick="DoSubmit()"

We should at least attempt to prevent double clicking the submit button,
so I use a global var (in the "buttons" frame) to track this.

When setting focus to another frame, IE5.0 ignores the focus change 
*unless* blur() is called first for the current frame.

In IE5.0, when setting focus to another frame, if the onchange event of 
the field which last had focus in that frame returns false, then 
IE5.0 gets an "unspecified error" on the focus() call. We will use a
try..catch to catch this and handle it.

var DidSubmit = 0;
function DoSubmit() {
    if (DidSubmit) return false; // don't submit twice
    DidSubmit = 1; // now inside submission
    blur(); // force ie5.0 to allow focus change to page frame
    try { 
        top.page.focus(); // force ie5.0 to call field onchange events
    } catch (e) { // catches validation errors (onchange returned false)
        DidSubmit = 0; // no longer inside submission
        return;
    }
    // any onchange event has succeeded
    // call onsubmit event manually (if any)
    if ( top.page.EntryForm.onsubmit==null // any onsubmit event?
         || top.page.EntryForm.onsubmit() )
        top.page.EntryForm.submit(); // do actual submission
    else
        DidSubmit = 0; // onsubmit failed, no longer inside submission
}

4) Submitting form inside same frame too

You should be certain that submission is handled exactly the same 
whether submitted in the "page" frame or by a button in the
"buttons" frame: if you can assume the "buttons" frame exist, then
use a button in the "page" frame to call the DoSubmit button in the
"buttons" frame.

In the "page" frame:
<button type=button onclick="top.buttons.DoSubmit()">Submit 
Form</button>

- Moe.