TurboManage

David Chandler's Journal of Java Web and Mobile Development

Swapping DIVs technique for navigation with gwt-presenter

Posted by David 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 portion of the page, and could be applied to the whole page, as well; however, here’s another simpler technique for situations in which you need to swap between totally unrelated views. For example, my main app has a header, footer, and content area in which views are swapped out using a WidgetContainerPresenter. However, I also need to replace the whole page (header, footer, and all) for a user registration page. To do this, I simply created two DIVs in the HTML host page:

		<div id="roa-registration"></div>
		<div id="container"></div>

My main AppPresenter loads all the presenters up front and fires a PlaceRequestEvent to the user registration presenter for new users. For existing users, it fires a PlaceRequestEvent based on the URL or to the default presenter if the URL is empty.

...
	public void go(final HasWidgets container)
	{
		this.container = container;
		loadMain();
		hideSplash();
		if (roaModel.getLoginInfo().getUser() != null)
		{
			showMain();
			String currentPlace = History.getToken();
			if ("".equals(currentPlace))
			{
				goToDefaultView();
			}
			else
			{
				// Load requested page
				placeManager.fireCurrentPlace();
			}
		}
		else
		{
			showRegistration();
		}
	}

	private void showRegistration()
	{
		// New user must register
		eventBus.fireEvent(new PlaceRequestEvent(new PlaceRequest(
			UserRegistrationPresenter.PLACE)));
	}

	private void hideSplash()
	{
		DOM.removeChild(RootPanel.getBodyElement(), DOM
			.getElementById(RoaStyles.ID_SPLASH));
	}

	private void loadMain()
	{
		// Hide while loading
		 DOM.setStyleAttribute(RootPanel.get(RoaStyles.CONTAINER_ID)
		 .getElement(), "display", "none");
		container.clear();
		HeaderPanel headerPanel = new HeaderPanel(roaModel.getLoginInfo());
		headerPanel.add(messagePresenter.getDisplay().asWidget());
		container.add(headerPanel);
		...
		container.add(bodyPanel);
		container.add(new FooterPanel());
	}

	private void showMain()
	{
		// Set GWT container visible
		DOM.setStyleAttribute(RootPanel.get(RoaStyles.CONTAINER_ID)
			.getElement(), "display", "block");
		// Load initial data
		prayerListService.refreshPrayerLists();
	}

	private void goToDefaultView()
	{
		// Nothing in URL, load default page
		eventBus.fireEvent(new PlaceRequestEvent(new PlaceRequest(
			ManageListsPresenter.PLACE)));
	}

Finally, I toggle the visibility of the two DIVs in the user registration presenter’s revealDisplay() method, which gets called in response to a PlaceRequestEvent. In addition, I call a hideDisplay() method in the presenter’s onBind() method (called from the constructor), so that its initial state is hidden.

	@Override
	public void revealDisplay()
	{
		super.revealDisplay();
		RootPanel.get(RoaStyles.CONTAINER_ID).setVisible(false);
		RootPanel.get(RoaStyles.REGISTRATION_CONTAINER_ID).setVisible(true);
	}

	public void hideDisplay()
	{
		RootPanel.get(RoaStyles.REGISTRATION_CONTAINER_ID).setVisible(false);
	}

The downside to this technique is that it would be a pain to manage with more than a few DIVs, as each presenter would have to know how to show itself and hide the others; however, for swapping between completely different page layouts, I think it’s easier than creating nested WidgetContainerPresenters (if that would even work). On the plus side, multiple presenters can use each layout (DIV), and most applications are likely to need only a handful of completely distinct page layouts. YMMV.

8 Responses to “Swapping DIVs technique for navigation with gwt-presenter”

  1. AlexH said

    I noticed there have been changes in gwt-presenter trunk since the 1.0.0. In
    particular with revealDisplay() being added to BasicPresenter. It looks like
    you are building from trunk rather than the 1.0.0. I’ve followed your
    approach and have found that my main view doesn’t display but instead my
    secondary view is being displayed on top. Off the top of your head, would
    there be changes in trunk that would impede your strategy in your blog from
    working? If not then I have made an error someplace in my coding and
    implementation of your technique.

    • Correct, I’m building from trunk (as of a couple weeks ago). I don’t think anything has changed on trunk that would cause the behavior you’re seeing, however. Rather, you may need to explicitly hide all but the DIV you want to show. Any widget you add to the RootPanel on down is visible by default, and gwt-presenter doesn’t change that. So you may want to explicitly hide all your views by default and then use a PlaceRequestEvent as this post discusses to reveal only one. You could do this by creating a hide() method in each Display interface and implementing it in your views with setVisible(false). Then call display.hide() in each presenter’s constructor or onBind() method. Also, this post has presenters calling RootPanel, which really should be moved into the corresponding views.

  2. AlexH said

    Hi,

    I took the time to upgrade my code to utilize the trunk in gwt-presenter. However, I discovered that my issue was that I had neglected to associate my views with the DIV’s defined in DOM. Oops. I think you are right however about moving more of the hide responsibility into the view class and working through the Display interface.

  3. AlexH said

    Another followup question:

    In my presenter when responding to a click event, would the proper way to fire an event to reveal another view look like this:

    eventBus.fireEvent(new PlaceRequestEvent(new PlaceRequest(
    UserPresenter.PLACE)));

    I have this code in place now but revealDisplay on the target view is not invoked. Sorry if I’m confused over the mechanism.

    • Yes, that’s it. Make sure that you’re overriding revealDisplay() in a presenter that extends WidgetPresenter. Also make sure your presenter constructor calls bind(), as the bind() method in the BasicPresenter (WidgetPresenter superclass) is what registers the listener for PlaceRequestEvents that in turn calls revealDisplay().

  4. alexharvey said

    Hi David,

    I was wondering if you have tested your DIV switching approach in IE 6. My implementation seems to work in all browsers except IE 6. In IE 6 if I hit refresh once after switching DIV’s then mysteriously it will begin to work on subsequent switches.

  5. Brakebg said

    Hi David,
    You always post interesting techniques, i would like to ask you a question which is not direct related to this topic here.
    Could you give me any tip how to develop header and footer for my gwt mvp application, the mvp implementation i m using is gwt presenter.

    Thanks in advance.

Leave a comment