iframe onLoad event in IE

416 views
Skip to first unread message

Essington

unread,
Jul 7, 2006, 2:01:48 PM7/7/06
to Google Web Toolkit
O.K. I'm down to one last issue in my little iframe post thing.

I create a named iframe, and I want it to handle onLoad events, so in
my constructor I add:

sinkEvents(Event.ONLOAD);

then later in my application I implement:

public void onBrowserEvent(Event event)
{
Window.alert("Browser Evernt: "+DOM.eventGetTypeString(event));
}

ONLOAD events are fired on Safari and Mozilla, but the event is not
fired on IE.

Any idea what the problem could be?

In desperation I even tried to sink a bunch of events in my
constructor:


sinkEvents(Event.ONLOAD|Event.FOCUSEVENTS|Event.KEYEVENTS|Event.MOUSEEVENTS|Event.ONCHANGE);

and found that IE would fire focus events, and mouse events, (and
probably key events too)
but still no onLoad or onChange events.

Is there some problem with sinkEvents and iFrames on IE? Iframes have
to fire onload events ... in fact, the dom inspector shows a load event
being fired, in the browser.

This frame is located in a floating dialog box if that makes any
difference.

any ideas would be appreciated.

-jason

Jason Essington

unread,
Jul 7, 2006, 6:06:35 PM7/7/06
to Google-We...@googlegroups.com
I have created a very simple project that demonstrates this problem
if any one is interested in looking at it.

sinkEvents(Event.ONLOAD) just doesn't appear to work with iframes in
IE although it does everywhere else.

iframeLoadTest.zip

Jim White

unread,
Jul 10, 2006, 4:08:30 AM7/10/06
to Google Web Toolkit
Yes, I've had the same problem. From what I've read IE only supports
ONLOAD for FRAMESETs.

http://www.faqts.com/knowledge_base/view.phtml/aid/15071

I've tried using FRAMESET, but can't get GWT to load at all that way.

Jason Essington

unread,
Jul 10, 2006, 10:50:40 AM7/10/06
to Google-We...@googlegroups.com
hmm, that appears to refer to IE5, does the same limitation apply to
IE6?

in the DOM inspector (an IE plugin) I see that a load event is being
fired in IE6, but my application never sees it.

-jason

Jim White

unread,
Jul 10, 2006, 9:52:08 PM7/10/06
to Google Web Toolkit
It's definitely a browser specific issue and I don't yet know whether
it is something that can be worked around by GWT or not.

Works:

OmniWeb 5.5 (Sneaky Peek 17)
Firefox 1.5 (Mac & Windows)
Camino 1.0
Opera 8.0 (Mac)

No Work:

Safari (1.3.2 & 2.0.4) - Get first ONLOAD but no subsequent ones.
IE6 - Never gets an ONLOAD at all.

jdc

unread,
Jul 11, 2006, 5:18:02 PM7/11/06
to Google Web Toolkit
jason,

i've been following your iframe problems (as i had the same issues
myself) and believe i've finally struck on somthing that works without
modifying gwt code (which i did a *lot* while debugging).

i have a Form class that extends ComplexPanel and a FormResponseFrame
that extends Widget. the FormResponseFrame uses an Impl to
createElement(), providing the necessary fork for IE6 (those not
familiar with the forking process, see how GWT handles the creation of
the XmlHttpRequest object for IE6 by looking at HTTPRequest.gwt.xml,
HTTPRequest.java, HTTPRequestImpl.java, and HTTPRequestImplIE6.java).

now for the code snippets.
here's the Form constructor

public Form(final String id, final LoadListener loadListener) {
setElement(DOM.createElement("form"));
DOM.setAttribute(getElement(), "id", id);
DOM.setAttribute(getElement(), "name", id);
DOM.setStyleAttribute(getElement(), "margin", "0px");
DOM.setStyleAttribute(getElement(), "padding", "0px");
iframe = new FormResponseFrame();
add(iframe);
setTarget(iframe.getUID());
iframe.addLoadListener(loadListener);
}

notice the Form is getting its own FormResponseFrame, which it uses as
its target when the Form is submitted. the LoadListener is handled by
the FormResponseFrame exactly as any SourcesLoadEvents implementation
would (see GWT's Image.java for an example). magic goes on in its
constructor however:

public FormResponseFrame() {
impl = (FormResponseFrameImpl)
GWT.create(FormResponseFrameImpl.class);
setElement(impl.createElement(uid));

sinkEvents(Event.ONLOAD);
}

now we come to the fork in the road. thanks to my
FormResponseFrame.gwt.xml file, the GWT compiler knows to use
FormResponseFrameImpl unless the user.agent is IE6:

<module>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name="com.google.gwt.user.User"/>
<!-- IE6 iframe name/load bug fork -->
<replace-with
class="com.sys.xii.client.ui.impl.FormResponseFrameImplIE6">
<when-type-is
class="com.sys.xii.client.ui.impl.FormResponseFrameImpl"/>
<when-property-is name="user.agent" value="ie6"/>
</replace-with>
</module>

so in all browsers but IE6, this FormResponseFrameImpl.createElement
method is called:
public Element createElement(final String uid) {
final Element iframe = DOM.createIFrame();
DOM.setAttribute(iframe, "name", uid);
DOM.setAttribute(iframe, "id", uid);
DOM.setStyleAttribute(iframe, "width", "0px");
DOM.setStyleAttribute(iframe, "height", "0px");
DOM.setStyleAttribute(iframe, "border", "0px");
return iframe;
}

but when the GWT compiler builds the pack file for IE6, it replaces it
with FormResponseFrameImplIE6.createElement:

public Element createElement(final String uid) {
final Element iframe = DOM.createElement("<iframe
name=\""+uid+"\" onload=\"window.__secretDonuts(this);\">");

DOM.setAttribute(iframe, "id", uid);
DOM.setStyleAttribute(iframe, "width", "0px");
DOM.setStyleAttribute(iframe, "height", "0px");
DOM.setStyleAttribute(iframe, "border", "0px");
makeSecretDonuts(iframe);
return iframe;
}

of course, this is how we makeSecretDonuts so that our iframe's onload
handler can call to the DOM.dispatchEvent() method:
public native void makeSecretDonuts(final Element element) /*-{
$wnd.__secretDonuts = function(element) {

@com.google.gwt.user.client.DOM::dispatchEvent(Lcom/google/gwt/user/client/Event;Lcom/google/gwt/user/client/Element;Lcom/google/gwt/user/client/EventListener;)($wnd.event,
element, element.__listener);
};
}-*/;

so the real problem turned out to be in DOMImplIE6.init() (a JSNI
method). we see that the $wnd.__dispatchEvent function is set up as:

$wnd.__dispatchEvent = function() {
if ($wnd.event.returnValue == undefined) {
$wnd.event.returnValue = true;
if
(!@com.google.gwt.user.client.DOM::previewEvent(Lcom/google/gwt/user/client/Event;)($wnd.event))
return;
}

var listener, curElem = this;
while (curElem && !(listener = curElem.__listener))
curElem = curElem.parentElement;

if (listener)

@com.google.gwt.user.client.DOM::dispatchEvent(Lcom/google/gwt/user/client/Event;Lcom/google/gwt/user/client/Element;Lcom/google/gwt/user/client/EventListener;)($wnd.event,
curElem, listener);
};

this works great for all manner of widgets...the assignment "var
curElem = this" works because "this" is the widget in question
receiving mouse or key events (the Image even manages to dispatch the
load event correctly). however, when the iframe's onload function is
set to $wnd.__dispatchEvent(), the "this" seems to refer to the window
rather than the iframe once we're in the body of the function. so
looking at the dispatchEvent function we see that the final call to
DOM::dispatchEvent is what we really want, we can hide that call in the
$wnd.__secretDonuts() function. realizing that $wnd is shorthand for
window, we can set our iframe's onload handler to
"window.__secretDonuts(this)", where "this" finally refers to the
actual iframe, and we can get ahold of the iframe's listener and
dispatch correctly.

please try the solution (feel free to adapt it to your code...that's
what i did with your iframe name fix for targeting in IE6) and let me
know if you need any clarification of the rambling explanation above.


jesse crossley

Essington

unread,
Jul 12, 2006, 9:51:16 AM7/12/06
to Google Web Toolkit
jesse

Great solution! I solved the problem in a similar way ...
I found that Moz had the annoying trait of calling onload when the
iframe was displayed with no content. so rather than fighting to get IE
to work, then fighting to filter the extraneous onload events in
mozilla, I moved the onload handler into the body of the returning
document.

Of course I had to solve the name problem of the iFrame in a similar
way (custom iframe implementation for ie and a rebind).

I added a javascript hook to call my handle response method (this is
similar to your __secretDonuts hook:

public native void setHook(Element element, PostCallbackFrame
myframe) /*-{
$wnd.doload =
function(){myframe.@com.grcs.orbit.web.client.ui.PostCallbackFrame::handleResponse()();};
}-*/;

then in my response I send:

<body onload="window.parent.doload()">

in this case it seems window refers to the iframe (I couldn't seem to
get the hook to work from there) and parent then refers to the same
window as $wnd.

this works perfectly on all platforms, and has the added benefit of not
firing extra onload events in mozilla.

-jason

jdc

unread,
Jul 12, 2006, 11:23:04 AM7/12/06
to Google Web Toolkit
that's not bad either. unfortunately for me, i'm POSTing a file upload
to an existing file service which only responds with the URL to access
the uploaded file (not even valid html), and i didn't have the
flexibility to modify the file service. my method actually results in
IE firing the empty onload event (the same as Moz does), but my
ultimate handler method checks for the empty string of the psuedo-load
and ignores it.

one possible gotcha to watch out for is if your main page gets put into
a frameset (like a portal or something), then the iframe's
onload="window.parent.doload();" might not refer to what you want it
to. that's one reason why i've always avoided scripting the iframe
contents; the other is that back in the days before XmlHttpRequest
objects, i would dump html into an invisible iframe, scrape it out
using the innerHTML property, and display it in a dialog window. this
scraping loses any script in the <head> of the iframe contents, but is
an admittedly weird thing to do.

Jason Essington

unread,
Jul 12, 2006, 11:31:03 AM7/12/06
to Google-We...@googlegroups.com

On Jul 12, 2006, at 9:23 AM, jdc wrote:

> back in the days before XmlHttpRequest
> objects, i would dump html into an invisible iframe, scrape it out
> using the innerHTML property,

This is exactly the use case that I have implemented ...

The innerHTML is actually serialized data (exactly the same as an RPC
response) so that my form posts (file upload or otherwise) can handle
exceptions and such in the exact same way that GWT RPCs do.

so, once the onload fires, it triggers a method that de-serializes
the response, and feeds it to an AsyncCallback!

The only difference between this method and the RPC is that if it
doesn't see the {OK}/{EX} prefix, it just assumes a string response
rather than pitching a fit.

Reply all
Reply to author
Forward
0 new messages