1

I'm trying to write a GWT app that reuses the same template for every "page" (place). There are 4 main "pages" of the app:

  • Dashboard page (http://www.mywebapp.com/#dashboard)
  • Calculator page (http://www.mywebapp.com/#calc)
  • Configurator page (http://www.mywebapp.com/#config)
  • Login page (http://www.mywebapp.com/#login)

Each "page" has the same templated look-and-feel: (1) a header section that contains the logo and the navigation menu, (2) a content section that contains "page"-specific content (i.e. will be different for the #dashboard place, #login place, etc.), and (3) a footer section that contains some links. So you see, the only thing that changes from page-to-page is the content section. Just like an ordinary, templated web site.

The thing is, each "page" (place) is actually a fairly complicated UI with many different panels consisting of lots of widgets. As the user interacts with the app, these panels will come into and out of existence and the display will be changing all the time. For instance, on the #calc page, the user can select which "mode" to display a calculator in: either as Basic or as Advanced. When the user selects Advanced, several additional panels will display (in addition to the Basic panel).

It would be nice to be able to keep such actions in history, so that the user can bookmark the app in either Basic or Advanced mode, so something like:

  • http://www.mywebapp.com/#calc/basic; or
  • http://www.mywebapp.com/#calc/advanced

Here's the problem:

We already have several "levels" of activities/places going on here. At the "app"-level, we have the template that needs to be displayed to the user when the MyWebAppModule implements EntryPoint downloads. This TemplatePlace is the default/initial place that is registered with the HistoryHandler before calling:

public class MyWebAppModule implements EntryPoint {
    @Override
    public void onModuleLoad() {
        // ...

        // The first place we go to when this module downloads.
        TemplatePlace templatePlace = getSomehow();

        historyHandler.register(placeController, eventBus, templatePlace);
        historyHandler.handleCurrentHistory();
    }
}

Next, we have all the different "pages": DashboardPlace, CalculatorPlace, etc. that all have their own unique views/displays. For instance when the user clicks the Calculator link to go to CalculatorPlace, it should render a different view than when the identify that they want to use the calculator in Basic or Advanced mode.

Finally, we have the different display regions, panels, etc. inside each page/place, such as the BasicCalculatorPlace and AdvancedCalculatorPlace. This is what I mean by different "levels" of navigation:

  1. Application-level (a template to apply to all pages/places)
  2. Page- or place-level
  3. Display- or panel-level

The question:

I want to achieve bookmarkable URLs (places) for when the user does all of the following:

  • Goes to the home page (http://www.mywebapp.com)
  • Goes to any of the "pages" (http://www.mywebapp.com/#calc, etc.)
  • Uses the pages/places which cause page-specific panel or display configurations (http://www.mywebapp.com\#calc\#advanced, etc.)

How many Activities and Places do I create? How many ActivityManagers? I guess I'm asking for how granular Activities/Places need to be for each "level" of bookmarkable UI. Thanks in advance!

1 Answers1

0

I think you only need one ActivityManager and one Activity per "page". You can make your "header" and "footer" into widgets that can be reused in each page.

You can bookmark different states of the same page by using tokens. For example, you can set a token to "basic" - it would tell the CalculatorActivity to show basic calculator panel. The URL will look like:

www.myApp.com/?#Calculator:basic

When a user clicks on a widget to select an advanced option, you do

PlaceController.goTo(new CalculatorPlace("advanced"));

The CalculatorActivity will get the CalculatorView (which is already displayed), it will see that the token is set to "advanced" and it will instruct this view to show advanced panels.

Note that you can make your tokens as detailed as necessary and then parse them in Activity. For example, you can have something like

www.myApp.com/?#Calculator:option=basic&position=top&theme=pink
Andrei Volgin
  • 40,755
  • 6
  • 49
  • 58
  • Thanks @Andrei Volgin (+1) - how do I achieve a more complex token in my PlaceHistoryMapper`, like your example of: `option=basic&position-top&theme=pink`? Is it literally as easy as *if(place instanceof CalculatorPlace) return "option=basic&position=top&theme=pink";* or is it more complicated? Thanks again! –  Nov 10 '12 at 21:59
  • Also, just for clarification: 1 `Place` subclass per page and 1 `ActivityManager` per page, but how many `ActivityMapper`s? Should there always be a 1-to-1 ratio between `ActivityManager`s and their `ActivityMapper`s, or can you pass the same `ActivityMapper` around to multiple managers? I think this is at the heart of my confusion regarding "granularity". –  Nov 10 '12 at 22:03
  • You only need one ActivityMapper and one ActivityManager for the entire app - not per page. This article explains it pretty well: https://developers.google.com/web-toolkit/doc/latest/DevGuideMvpActivitiesAndPlaces. Also look at some examples: http://code.google.com/p/gwt-examples/wiki/DemoActivitiesAndPlaces – Andrei Volgin Nov 10 '12 at 23:01
  • But if you only have 1 ActivityManager for you app, which means its `setDisplay(AcceptsOneWidget)` can only hold one widget at a time, how do you have multiple dislpay regions on the same screen that can be updated independently of one another? –  Nov 11 '12 at 00:43
  • If you want to go with multiple regions, read Thomas' brilliant post: http://tbroyer.posterous.com/gwt-21-activities-nesting-yagni However, if you simply need a menu and a footer, you can make them into widgets and simply include them in each page where you need them. For example, your main widget that you pass to AcceptsOneWidget can be a LayoutPanel (or DockLayoutPanel). Menu widget will take the top part, footer widget the bottom part, and then you add your page-specific panels in the middle. Including the same widget on several pages will not increase your code size. – Andrei Volgin Nov 11 '12 at 02:45