Showing posts with label Handler. Show all posts
Showing posts with label Handler. Show all posts

Friday, July 16, 2010

How to create a custom event handler in GWT

After struggling for longer than I should have I need to document the process partly for my own benefit and because if I struggled then someone else probably will as well.   So what am I documenting.

Scenario:
You have created a custom control Composite and want to implement a custom event for your control.  For example in the same way a button has a click event which is handled by the controls that use it.

Technology:
GWT 2.0, Java

Solution Outline:
In this example we are using a paging control as the example.  This is a custom control that aims to replicate the kind of functionality as seen in the next, first, prev, last and message functionality when navigating between emails.

Step 1: Create the custom event - PageChangedEvent

The PageChangedEvent will be fired when ever a paging action takes place.  For instance if a move next, prev, first or last action is called.  The code is pretty self explanatory but for clarity I have separated the code into the boiler-plate section and the code specific to this event.



public class PageChangedEvent extends GwtEvent<PageControlHandler> {
// Boiler plate code required to make your event work correctly in the GWT system
private static final Type<PageControlHandler> TYPE = new Type<PageControlHandler>();

@Override
public com.google.gwt.event.shared.GwtEvent.Type<PageControlHandler> getAssociatedType() {
return TYPE;
}
@Override
protected void dispatch(PageControlHandler handler) {
handler.onPageChanged(this);
}
// Code specific to this custom event

public enum PageChangeType {
first, prev, next, last
}
private final PageChangeType pageChangeType;

public PageControlEvent(PageChangeType pageChangeType) {
this.pageChangeType = pageChangeType;
}

public static Type<PageControlHandler> getType() {
return TYPE;
}
public PageChangeType getPageChangeType(){
return pageChangeType;
}

}


Step 2 : Advertise that this control has this types of events
In the PageControl which has these kinds of events we need to advertise this fact to the other classes, therefore the control will advertise this by implementing an interface called HasPageChangedHandler:


public class PageControl extends Composite implements ClickHandler, HasPageChangedHandler {


However this interface has yet to exist so we need to create it:


import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.event.shared.HasHandlers;


public interface HasPageChangedHandler extends HasHandlers {


  public void addPageControlHandler(PageChangedHandler handler);
}


This invites other parent controls to use this event by registering a PageChangedHandler with this control

Step 4 : Create the PageChangedHandler Interface
The handler interface indicates what type of events, or methods are required when implementing a handler of this type:


import com.google.gwt.event.shared.EventHandler;


public interface PageChangedHandler extends EventHandler{

 void onPageChanged(PageChangedEvent event);


}


Step 5 : Implement the methods in the composite control
In Step 2 we implemented an interface, and Step 3&4 we created those interfaces now we need to go back to the PageControl and the unimplemented methods.


@Override
public void addPageChangedHandler(PageChangedHandler handler) {
addHandler(handler, PageChangedEvent.getType());
}



This is an important step.  This registers the handler for this type of event.  The "addHandler" method is part of the GWT Widget class and is native to GWT.  Therefore this method doesn't need to be created.

Step 6 : Wire up the parent control to respond to onPageChangedEvents
There are a myriad of ways of doing this but assuming the parent control has only one page control then I wired it up by implementing the PageChangedHandler onto the main class:


public class MainSearchPresenter extends PresenterImpl<MainSearchPresenter.MyView, MainSearchPresenter.MyProxy>
implements SearchChangedHandler, ContactAddedHandler, ShowSearchResultsHandler, PageChangedHandler {

Which then shows the method that is run when a PageChangedEvent is called:
@Override
public void onPageChanged(PageChangedEvent event) {
if (event.getPageChangeType() == PageChangeType.next) {
getView().setupPager(1l, totalRecords, 20l);
}
}

However this will not work yet as we haven't registered this class as being ready to accept incoming onPageChanged requests from the pageControl.  Therefore whereever you bind up your controls, which will differ depending on what framework you use then you will need to add something like this:

pageControl.addPageChangedHandler(this);

If you were implementing this an anonymous inner class then this kind of setup would be used, which is very similar to the click handlers which are often implemented.

pageControl.addPageChangedHandler( new PageChangedHandler(){



@Override
public void onPageChanged(PageChangedEvent event) {
if (event.getPageChangeType() == PageChangeType.next) {
getView().setupPager(1l, totalRecords, 20l);
}
}
});


Step 7 : But wait - how do I fire this event from the child control?
Using whatever constructor arguments you require depending on the  type of event to fire then you simply call the composites native fireEvent method.



  this.fireEvent(new PageChangedEvent(PageChangeType.first));




Conclusion
This took me a day to figure out.  Ouch.  A lot of it had to do with getting confused with the old listeners method.  Which you should ignore if you are using 2.0 GWT or higher.  But there were plenty of code examples, which weren't quite complete.  I am hoping that this might help a newbie in the future like myself understand this process better.