Navigating to a new view with gwt-presenter
Posted by David Chandler on October 1, 2009
How can you move to a new “view” with gwt-presenter? In GWT, you wouldn’t ordinarily replace the entire page as in a server-side Web app. Suppose you have one area of the screen, say, a VerticalPanel, in which you want to show any number of functional views (i.e, manage lists, edit list properties, etc.). One way to do this is using a DeckPanel, which is the base class behind GWT’s TabPanel widget. DeckPanel has no visible UI controls, but lets you programatically swap out one widget for another just as if you were clicking tabs. Gwt-presenter provides DeckPresenter and DeckDisplay to help with just that. Here’s a sample DeckPresenter class.
package com.roa.client.presenter; import net.customware.gwt.presenter.client.EventBus; import net.customware.gwt.presenter.client.place.Place; import net.customware.gwt.presenter.client.place.PlaceRequest; import net.customware.gwt.presenter.client.widget.DeckDisplay; import net.customware.gwt.presenter.client.widget.DeckPresenter; import net.customware.gwt.presenter.client.widget.WidgetContainerDisplay; import net.customware.gwt.presenter.client.widget.WidgetPresenter; public class ContentContainerPresenter extends DeckPresenter { private static final Place PLACE = new Place("content"); public interface Display extends WidgetContainerDisplay { } public ContentContainerPresenter(DeckDisplay display, EventBus eventBus, WidgetPresenter<?>[] presenters) { super(display, eventBus, presenters); bind(); // One way to show default presenter--see also AppPresenter below for another way // showPresenter(presenters[0]); } @Override public Place getPlace() { return PLACE; } @Override protected void onPlaceRequest(PlaceRequest request) { // TODO Auto-generated method stub } }
And here’s the corresponding view:
package com.roa.client.ui.web.content; import net.customware.gwt.presenter.client.widget.DeckDisplay; import com.google.gwt.user.client.ui.Widget; public class ContentContainerView extends DeckDisplay { public ContentContainerView() { } @Override public void addWidget(Widget widget) { super.add(widget); } @Override public void removeWidget(Widget widget) { super.remove(widget); } @Override public void showWidget(Widget widget) { // Refer up to DeckPanel super.showWidget(widget); } @Override public Widget asWidget() { return this; } @Override public void startProcessing() { // TODO Auto-generated method stub } @Override public void stopProcessing() { // TODO Auto-generated method stub } }
Gwt-presenter’s DeckDisplay, unlike the other gwt-presenter interfaces named “Display”, is actually a concrete class that extends GWT’s DeckPanel. As such, we can use it as our view implementation directly. Now let’s wire them up. Because DeckPresenter’s constructor takes an array of presenters as an argument, there’s no way (that I know of, at least) to instantiate it with GIN using @Inject. So in our AppPresenter, we manually construct the needed classes like this:
@Inject private EventBus eventBus; @Inject private ManageListsPresenter listsPresenter; @Inject private AddPrayerListPresenter addPresenter; ... // Instantiate container presenter manually as its constructor // prevent GIN binding WidgetPresenter<?>[] presenters = new WidgetPresenter<?>[] { listsPresenter, addPresenter }; ContentContainerView contentContainerView = new ContentContainerView(); ContentContainerPresenter contentContainerPresenter = new ContentContainerPresenter( contentContainerView, eventBus, presenters); // Fire event to reveal only default presenter eventBus.fireEvent(new PresenterRevealedEvent(listsPresenter));
In order to show the default presenter (in this case, Manage Lists), we fire a PresenterRevealedEvent after constructing the ContentContainerPresenter. Without it, however, the default behavior of GWT presenter is to show the widgets associated with all presenters that have been added to the container.
Finally, we need to fire an event to transition from one view to another. We could use a PresenterRevealedEvent; however, the PlaceRequestEvent does much more. Gwt-presenter’s BasicPresenter class (from which WidgetContainerPresenter and DeckPresenter are derived) listens for PlaceRequestEvents, marks the Place in History, calls onPlaceRequest() for the requested presenter, and finally calls the requested presenter’s revealDisplay() method, which in turn fires a PresenterRevealedEvent.
The code below will trigger a transition from the ManageListsPresenter to the AddPrayerListPresenter when the add button is clicked. The easiest way to get a reference to the presenter we’re going to is simply to make its PLACE constant public so we can use it in PlaceRequests from other classes.
public class ManageListsPresenter extends WidgetPresenter<ManageListsPresenter.Display> { display.getAddButton().addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { PlaceRequest placeRequest = new PlaceRequest(AddPrayerListPresenter.PLACE); eventBus.fireEvent(new PlaceRequestEvent(placeRequest)); } }); ... }
Swapping DIVs technique for navigation with gwt-presenter « TurboManage said
[…] Chandler on October 21, 2009 I have previously written about navigation in gwt-presenter using the DeckPresenter or WidgetContainerPresenter approaches. Those techniques work well for swapping out views in one […]
brakebg said
Good post but the last example where you use PlaceRequest to trigger transition has one disadvantages according to me, it does not change the token in the url.
David Chandler said
Been a while since I’ve looked at this, but if everything is wired up properly, it should in fact change the URL. That’s the magic of gwt-presenter.