DOM-Eventhandling in GWT

GWT provides wrappers for all standard DOM-events and a unified interface for handling them. This article aims to provide a full listing of all relevant classes and points of interest for solving problems related to the DOM event cycle.

GWT event-handling is seperated from DOM events, which are wrapped with the NativeEvent class. The DomEvent class is a subclass of GwtEvent, which implements the flyweight pattern to wrap DOM-events and provide behaviour consistent with the GWT event-handling.
This makes it possible to handle DomEvents in the same way as regular GwtEvents, while the former are triggered by the browser itself.

The link to the browser is realized in the DOMImplStandard.sinkEventsImpl(Element, int) method. In this native method, DOM EventListeners are added to the DOM elements representing GWT Widgets. This method is ultimately executed when the addDomHandler() method is called. It effectively overrides all eventlisteners set by the browser with a method triggering the GWT event-cycle, so calling event.preventDefault() and event.stopPropagation() on a DomEvent are sure to have the desired effect.

Adding EventListeners in JavaScript

As stated above, GWT does this for all standard DOM-events by default. To capture events not handled by GWT (for example touch-events), it may be necessary to do this manually, using native JavaScript.

There are two (and a half) ways to add an event-listener to a DOM element (in plain HTML/Javascript surroundings), to slightly different effects. The "default" approach is to use the addEventListener method of the DOM elements:

addEventListener(in DOMString type,
                 in EventListener listener,
                 in boolean useCapture);

Where "type" is the event-parameter (e.g. "mouseover"); "listener" can be an anonymous function which takes an event as parameter. The "useCapture" parameter specifies whether the function should be called in the capture-/trigger-phase (if true) or in the bubbling-phase (if false).
This will add the eventlistener to the element, so previous listeners will stay intact.

However, if you want to replace all other listeners, you can set the listener directly by assigning a javascript function directly to the appropriate attribute, which is the name of the event in question (not the type!). For example, the following code would listen for mouseover events:

element.onmouseover = function (e) {
                          // handle event e...
                          // for example, stop the event's propagation
                          e.stopPropagation();
                      };

Note that this approach will always register then listener for the bubbling phase, not the capture phase. This is equivalent to setting the HTML-tag's attribute. Also, any listeners you added using addEventListener() for a DOM event before setting the listener like this will be lost.

See the DOM Level 3 specification on the EventTarget interface for details on the behaviour of an event-listener function (http://www.w3.org/TR/DOM-Level-3-Events/#interface-EventTarget).

Debugging in the Browser

When debugging issues with the DOM event-handling, a good point to start is to check the "Event Listeners" property of the DOM element. All DomEvents which have been added using addHandler() should be visible here - the most common reason for event-handling not working is that addHandler() was not called ;-).

In some browsers, stopping the propagation of "lower-level" events (such as click events) can prevent other DOM events (like the contextmenu event) from being triggered. This can be the source of near-endless frustration, especially with browsers like Chrome/Chromium, which implement major parts of their own user-interfaces in javascript/html.

The following links provide essential information for understanding the DOM event-handling and associated problems: