Building a GWT 1.6 application: Managing events with an eventBus

posted on June 19, 2009 in coding

GWT 1.6 gets rid of all the Listener classes, and replaces them with the new Handler classes. For a comparison of the two, Jason from Lemming Technology Blog has a good overview.

At Google I/O, Ray Ryan talks about best practices for architecting your GWT app. There he mentions using an Eventbus to manage your events, and even provides some example code. Still, it all seemed a bit confusing, so I made a little testapplication to test it out.

Some points to consider:

1. The only thing passed around is the eventBus itself. This can be done with Dependency Injection, with a Registry Pattern, or whatever floats your boat. In this case DI is used.
2. For each new type of event added, a new event class must be created:

public class TableRowEvent extends GwtEvent<tableRowEventHandler> {
 
	/**
	 *  For each new event, a new event type must also be specified,
	 *  with which the event can be registered
	 */
	public static final GwtEvent.Type<tableRowEventHandler> TYPE
		= new GwtEvent.Type<tableRowEventHandler>();
 
 
	/*
	 * required
	 */
	@Override
	protected void dispatch(TableRowEventHandler handler) {
		handler.onAddRow(this);
	}
 
	/*
	 * required
	 */
	@Override
	public GwtEvent.Type<tableRowEventHandler> getAssociatedType() {
		return TYPE;
	}
}

3. … and associated eventHandler Interface:

public interface TableRowEventHandler extends EventHandler {
	/**
	 * What to do when a TableRowEvent is called
	 * @param addTableRowEvent
	 */
	void onAddRow(TableRowEvent addTableRowEvent);
}

4. Add the handler to the listening object:

public class SpecialTable extends FlexTable {
 
	// local reference to the eventBus
	HandlerManager eventBus;
 
	private void listenToAddRowEvent()
	{
		// registering the object to the eventBus
		eventBus.addHandler(TableRowEvent.TYPE, new TableRowEventHandler(){
		public void onAddRow(TableRowEvent event) {
			// do something
		}
	});
}

5. Fire the event on the specified occasion:

HandlerManager eventBus;
// in this case: a function in a button
private void initialize()
	{
	this.addClickHandler(new ClickHandler(){
		public void onClick(ClickEvent event) {
			// creates a new event, if desired additional data can be sent
			TableRowEvent sent = new TableRowEvent();
			eventBus.fireEvent(sent);
		}
	});
}

And there it is, your eventBus is up and running! And since both action(the button) and reaction(the table) are now completely separated, the timing of the event is no longer imporant.
Next Up:
- Adding testing.
- Adding MVP.
- working with GIN.
- …

15 Comments »

  1. How does this work if the screen has multiple special tables?

    Comment by Will — June 22, 2009 @ 3:55 pm

  2. I’d expect it to update both tables, since they both initialize the same handler. Which it does.

    The only ‘problem’ happens when your table isn’t initialized yet. For example with a lazyPanel. I’m not sure how to solve that, perhaps by extending the onLoad function?

    Comment by Maarten — June 22, 2009 @ 4:44 pm

  3. What if there is Table1 with button Add1 and Table2 with button Add2? How would Table2 respond only to Add2 button click, ie. Table2 should not add row when Add1 button clicked.

    Comment by Will — June 22, 2009 @ 9:38 pm

  4. If both the tables, buttons and events are identical, you could add a shared parameter to the event, pass it on in the button, read it out in the table and do something based on that parameter.
    Though I have trouble thinking of an application where that would be necessary.

    Comment by Maarten — June 22, 2009 @ 10:16 pm

  5. Thanks, for You article! I walking on your steps!
    Wait for new ideas about GIN

    Comment by Vetal — June 23, 2009 @ 5:55 pm

  6. It looks like the event source is not used. Is this en fact the case? Also, you mention in the sample code:
    /**
    * Adds Click Handler: when clicked, a
    * … TableRowEvent is sent to the eventBus
    * … (and fired)
    */
    private void initialize()
    {
    this.addClickHandler(new ClickHandler(){
    public void onClick(ClickEvent event) {
    // creates a new event,
    // … if desired additional
    // … data can be sent
    TableRowEvent sent =
    new TableRowEvent(); eventBus.fireEvent(sent);
    }
    });
    }

    Do you mean that the class reproduces the event.source (or any other private data)?

    I don’t see any way to gain access to the private “source” member since the single instance of HandlerManager is created with event.source = NULL

    Comment by fred — June 23, 2009 @ 7:09 pm

  7. At the google I/O session, Ray mentions the concept that the targets of event shouldn’t have to know who or what fired the event. Just that the event was called, if necessary with additional parameters. For example if you want to create a textbox with a button, you could create a composite containing both elements, give that composite a handler, and add a textValue field to the event class. You can then set the that parameter with event. setTextValue(someTextBox.getText()) and request it with event.getTextValue() or whatever you want.

    Comment by Maarten — June 23, 2009 @ 10:58 pm

  8. Exactly. The “source” member is ignored. I’d suspect that in the next iteration(s) of GWT, the idea of an “event source” mutates into something more flexible.
    My intention was to re-use “source” for my own events. Instead, it’s now a private member in an abstract class.
    Thanks for the example program. I found it quite helpful

    Comment by fred — June 24, 2009 @ 8:13 pm

  9. What is your approach for the following cases. Will you create custom events for every interaction? Or handle certain events with in the Widget UI?
    1) Events with in a widget.
    – Say validating input box?
    2) Intra widget events
    – On click of a link showing a dialog that displays information based on the data user entered.
    3) Navigational events
    – User clicks a button to navigate to another page.
    4) RPC calls.

    Comment by Ramesh — June 25, 2009 @ 11:04 pm

  10. One of the main lessons in the presentation is the importance of decoupling (and testing) and how one can use an eventBus or MVP to make it work. So keeping this in mind (for the record: these are just my opinions):
    1. validation: If the validation is not dependent on some external library: keep it in the presenter, don’t use events.
    2, 3 & 4: all based on multiple presenters or interactions with exernal sources: use events.

    Comment by Maarten — June 26, 2009 @ 3:44 pm

  11. Kudos on the good work representing gwt eventbus!
    Its been quite difficult to find proper
    eventbus examples to explain how to do this, and your’s is the best one i could find.
    Thanks so much!

    Comment by DAvid — August 5, 2009 @ 11:07 pm

  12. [...] see : Use MVP , MVP based Component Library, GWT MVP Sample, eventbus and mock [...]

    Pingback by GWT Atchitecture anyone? « TechnoBuzz — August 17, 2009 @ 3:35 am

  13. This was the clearest explanation of the EventBus I’ve seen. Well done and thank you!

    Comment by Eddie Chan — September 14, 2009 @ 1:19 pm

  14. Having recently started to learn how to use GWT and after looking at the event bus presentation I still had a few questions but after reading your article I feel I now know how this is done.

    Thank you for this great help.

    Comment by Rob — August 3, 2010 @ 2:07 pm

  15. Thank you. This is simple and good example and I finally understand GWT eventbus concept. And now,….,back to coding.

    Comment by Janez — September 17, 2010 @ 12:44 pm

RSS feed for comments on this post. TrackBack URI

Leave a comment

Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

-->

Blom Inrichtingen - interieurprojecten in de gezondheidszorg