Multiple pages tutorial in Google Web Toolkit (GWT)

Maksim picture Maksim · Jun 30, 2009 · Viewed 60.6k times · Source

I just started learning Google Web Toolkit (GWT). How do I make different HTML pages in my GWT application?

For example, I want to create an application for a book store. In this application I'll have three pages:

  1. Home pages where I will welcome the user and offer the user books
  2. Page to browse books by categories and view details (use GWT widgets)
  3. Check out books online.

Of course there could be other pages like the user's details, add new book, etc. So, what is the best way of making different pages in GWT and how can I make navigation from page to page? Are there any examples or tutorials? Or do I even need to create different pages when I can create a whole application in one page?

Answer

Chris Ruffalo picture Chris Ruffalo · Jun 30, 2009

What I usually do in situations like this is design the webpage framework first. I'll have a div for the header, side menu and footer. I'll also have a div in my HTML for the main content.

Example:

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta name='gwt:module' content='org.project.package.Core=org.project.package.Core'>
    </head>
    <body>
        <!-- Load the JavaScript code for GWT -->
        <script language="javascript" src="ui/org.project.package.ui.Core.nocache.js"></script>

        <!-- For some unknown reason in Internet Explorer you have to have cellpadding/spacing ON THE ELEMENT and not on the STYLE if it is in the body tag like this -->
        <table id="wrapper" cellpadding="0" cellspacing="0" style="width: 100%;height: 100%;">

             <!-- Header row -->
             <tr style="height: 25%;">
                 <td colspan="2" id="header"></td>
             </tr>

             <!-- Body row and left nav row -->
             <tr style="height: 65%;">
                 <td id="leftnav"></td>
                 <td id="content"></td>
             </tr>

             <!-- Footer row -->
             <tr style="height: 10%;">
                <td colspan="2" id="footer"></td>
             </tr>

        </table>

        <!-- This iframe handles history -->
        <iframe id="__gwt_historyFrame" style="width:0;height:0;border:0"></iframe>
    </body>
</html>

(If you like <div> based layouts, feel free to use those instead.)

Then you build your entry point (in my case Core.java) as you normally would, setting each of the elements as need be.

RootPanel.get("header").add(new Header());
RootPanel.get("leftnav").add(new NavigationMenu());
RootPanel.get("footer").add(new Footer());

It is, of course, possible to have a static footer and header, but that's neither here nor there.

I also have an abstract class called "Content". Content objects extend "Composite" and will have various methods for simplifying the creation and layout of a new page. Every page that I build for this application, be it a help screen, search screen, shopping cart, or anything else, is of type Content.

Now, what I do is create a class called "ContentContainer". This is a singleton that is responsible for managing the "content" element. It has one method "setContent" that accepts objects of type "Content". It then basically removes anything within the "content" <td> and replaces it with whatever widget (Composite) you assign via the "setContent" method. The setContent method also handles history and title bar management. Basically the ContentContainer serves to aggregate all the various points of binding that you might have to make if each page content had to "know" about all the functions it must perform.

Finally, you need a way to get to that page, right? That's simple:

ContentContainer.getInstance().setContent(new Search());

Put the above in an on-click event somewhere and you're golden.

The only things that your other widgets need to be bound to is the ContentContainer and the type of Content that they are adding.

The downsides that I can see to ChrisBo's approach are that you've got a list that has to be maintained of tokens -> pages. The other downside I can see is that I don't see how you can have an actual history system with this method.

One thing it does offer over my approach is that all page choices are pretty centralized. I'd use some sort of Enum or at least a static class with String values to prevent myself from mongling up links.

In either case, I think the point can be summed up as this: swap the content of some central page element based on what your user clicks actions your user(s) perform.