3

I've implemented a basic GWT app based on on the MVP pattern Google recommends. What I'm trying to figure out is the best way to store navigation/history state once you fill your application with data.

Let's say you have a search that returns a bunch data into a CellTable. If I navigate to a specific item in the search result to another panel, the initial Panel with the search result is gone unless the Presenter/View is stored somewhere so I can access it easily on a back navigation.

So, my question is, what do apps like Gmail do to preserve the state for back navigation? Are there any examples of how this can be implemented?

kapandron
  • 3,546
  • 2
  • 25
  • 38
stuff22
  • 1,662
  • 4
  • 24
  • 42

3 Answers3

2

Gmail doesn't use GWT, so I'm assuming you just want a high-level answer.

Gmail uses the URL fragment (the part after the #). As you navigate around in Gmail you'll notice that the fragment changes to a unique identifier for each "location" in Gmail's navigation. Using the fragment makes the browser do all the tracking for you without requiring page reloads. You then just monitor the fragment, and when it changes you navigate to the location it specifies.

Laurence Gonsalves
  • 137,896
  • 35
  • 246
  • 299
  • Yes, I've seen that. But, I've also noticed that it sometimes caches the result, and sometimes it goes back and loads it when you go back. So, if you would translate that behavior to a GWT app, what would it look like. Is it ok to cache the Presenters on the client in some kind of a Hashmap and based on the history token retrieve them from the map with the preserved state? I have some ideas on how to do this, I would just like to know if there's a more acceptable/better way of doing this before I start implementing it. – stuff22 Dec 09 '10 at 17:46
  • By default, the browser will not force a reload. You will have to provide the logic that determines whether the display is refreshed or not. This is a good way of doing things - go ahead and start implementing it! – Riley Lark Dec 09 '10 at 18:26
1

There are several MVP library projects for GWT that use the concept of a Place to represent the state of Presenters. Place implementations generally map the state to the URL fragment after the #. Hence, they work similarly to Gmail's state handling.

As an example, using the gwt-presenter project, you may have a DataPresenter and a DataPlace:

public class DataPlace extends ProvidedPresenterPlace<DataPresenter> {

@Inject
public DataPlace(Provider<DataPresenter> presenter) {
    super(presenter);
}

@Override
public String getName() {
    return "data";
}

@Override
protected void preparePresenter( PlaceRequest request, DataPresenter presenter ) {
    String state = request.getParameter("state", null);
    if (state != null) {
        // set the presenter state
        presenter.setState(State.valueOf(state));
    }
}

@Override
protected PlaceRequest prepareRequest( PlaceRequest request, DataPresenter presenter ) {
    return request.with("state", presenter.getState().toString());
}
}

When the URL has the form /data#state=12345, this Place will be asked to prepare the Presenter based on the parameters. Afterwards, the reveal method in the Presenter will be invoked. Since the state was already prepared by the Place, you'll be able to restore the view as needed.

LeonT
  • 56
  • 2
  • I guess I'm a little confused as to why I need to use a separate library for MVP when GWT 2.1 already implements this pattern. What is the difference between the two? I would assume that this would be solvable without using an external library. – stuff22 Dec 09 '10 at 18:27
  • That's an example from older 1.7 code. I haven't touched 2.1 yet, so you might find something better there. :) – LeonT Dec 09 '10 at 18:28
1

Where do you create Activities? You should return an existing activity instead of creating a new one every time a place changes. Activities are usually created in ActivityMapper. You have two options:

  1. Change ActivityMapper so that it creates an Activity instance on first invocation, and return this instance on subsequent invocations. Or,

  2. Use CachingActivityMapper to wrap your ActivityMapper. It will return an existing Activity instead of creating a new one.

Peter Knego
  • 79,991
  • 11
  • 123
  • 154