Matt RaibleMatt Raible is a Java Champion and Developer Advocate at Okta. developer.okta.com

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.

GXT's MVC Framework

For the past couple of months, I've been developing a GWT application using a mix of plain ol' GWT and GXT widgets. When I first started developing it, I didn't know how to best organize my code and separate the logic. The solution I came up with was to adopt some sort of MVC framework. Since I was already using GXT, I opted for GXT's lightweight MVC implementation.

As mentioned in Testing GWT Applications, GXT's MVC doesn't have much documentation. The best reference documentation seems to be Christian's Getting started with Ext-GWT: The Mail reference application.

Page Transitioning with Dispatcher
After working with GXT MVC for a couple months, I'm still not sure I fully understand how navigation and event dispatching works. The biggest point of confusion for me is how to best use GXT's Dispatcher class.

The problem with Dispatcher is it has a two methods that seem to do the same thing.

  • forwardEvent (4 variations)
  • dispatch (3 variations)

In addition to these methods in Dispatcher, there's two fireEvent methods in GXT's View class. According to my calculations, that means there's 9 different options for transitioning from one view to the next. Which one is best to use?

From what I've learned, I think it's best to use fireEvent in Views and forwardEvent in Controllers and other widgets. IMO, dispatcher should never be used except in your HistoryListener's implementation onHistoryChanged method. The important thing to realize about this method is it should only work if the View's Controller is registered for the event.

  protected void fireEvent(AppEvent event) {
    Controller c = controller;
    while (c != null) {
      if (c.canHandle(event)) {
        c.handleEvent(event);
      }
      c = c.parent;
    }
  }

However, fireEvent seems to work even when the View's Controller isn't registered for that event. This is because onHistoryChanged gets called in the EntryPoint. For experienced GXT MVC users, does this navigation handling mesh with your findings?

The most important thing for navigation to work successfully is enabling History support. The next section talks about how to do this effectively.

Enabling History Support
To help explain things better, I created a simple GWT MVC Example application and used Maven to create an archetype with it. You can create a project from the archetype using the following command:

mvn archetype:create -DarchetypeGroupId=org.appfuse.archetypes \
-DarchetypeArtifactId=gwt-mvc -DarchetypeVersion=1.0-SNAPSHOT \
-DgroupId=com.mycompany.app -DartifactId=myproject \
-DremoteRepositories=http://oss.sonatype.org/content/repositories/appfuse-snapshots

To enable history support in this application, I implemented HistoryListener in my EntryPoint (Application.java) and added the following logic to initialize:

// If the application starts with no history token, redirect to 'home' state
String initToken = History.getToken();
if (initToken.length() == 0) {
    History.newItem(HistoryTokens.HOME);
}

// Add history listener
History.addHistoryListener(this);

// Now that we've setup our listener, fire the initial history state.
History.fireCurrentHistoryState();

In this example, HistoryTokens is a class that contains all the URLs of the "views" in the application.

public class HistoryTokens {
    public static final String HOME = "home";
    public static final String CALENDAR = "calendar";
    public static final String NOTES = "notes";
    public static final String SEARCH = "search";
}

In order to make URLs like http://localhost:8080/#calendar go to the calendar view, the following logic exists in the onHistoryChanged method.

        Dispatcher dispatcher = Dispatcher.get();

        if (historyToken != null) {
            if (historyToken.equals(HistoryTokens.HOME)) {
                dispatcher.dispatch(AppEvents.GoHome);
            } else if (historyToken.equals(HistoryTokens.CALENDAR)) {
                dispatcher.dispatch(AppEvents.Calendar);
            } else if (historyToken.equals(HistoryTokens.NOTES)) {
                dispatcher.dispatch(AppEvents.Notes);
            } else if (historyToken.equals(HistoryTokens.SEARCH)) {
                dispatcher.dispatch(AppEvents.Search);
            } else {
                GWT.log("HistoryToken '" + historyToken + "' not found!", null);
            }
        }

Controllers are registered in the EntryPoint as follows:

        final Dispatcher dispatcher = Dispatcher.get();
        dispatcher.addController(new CalendarController());
        dispatcher.addController(new HomeController());
        dispatcher.addController(new NotesController());
        dispatcher.addController(new SearchController());

Controllers respond to events they're registered for. This is done in their constructor:

    public CalendarController() {
        registerEventTypes(AppEvents.Calendar);
    }

In order for navigation to work, you have to create links with history tokens1. For example, here's a link from the HomeView class:

	Hyperlink notesLink = new Hyperlink("Notes", HistoryTokens.NOTES);
	notesLink.addClickListener(new ClickListener() {
	    public void onClick(Widget widget) {
	        Dispatcher.get().fireEvent(AppEvents.Notes);
	    }
	});

You'll notice in this example, I'm using Dispatcher's fireEvent method. If I wanted to pass some data with your event, you'll need to use forwardEvent. Here's an example from CalendarView:

    Button submit = new Button("Submit");

    submit.addSelectionListener(new SelectionListener<ButtonEvent>() {
        public void componentSelected(ButtonEvent ce) {
            AppEvent<Date> event = 
                new AppEvent<Date>(AppEvents.GoHome, date.getValue(), HistoryTokens.HOME);
            Dispatcher.forwardEvent(event);
        }
    });

In this example, you could also use Dispatcher.dispatcher(), but I believe this will cause the transition to happen twice because the onHistoryChanged method gets called too. This doesn't matter for the most part, except when you start to use DispatcherListeners.

Hopefully this article has helped you understand how GXT's MVC framework works. I'm interested in learning how other GWT MVC frameworks work. If you've used one, I'd love to hear about your experience.

Friday Fun Test
Here's a test for those interested in digging into the GXT MVC example. There's a bug in this application that prevents something from happening. I'll buy a drink for the person that finds the bug and I'll buy two drinks for the person that comes up with a solution. ;-)

1. If you use the default constructor on Hyperlink and use setText(), make sure to call setTargetHistoryToken() too. If you don't, a blank history token will be used and # causes the browser to scroll to the top before a page transition happens.

Posted in Java at Mar 13 2009, 11:48:41 AM MDT 25 Comments
Comments:

Matt, very timely post, as I'm just getting started with GXT MVC too (and GWT), trying to wrap my head around it and figure out the best place to do things like RPC and where should the AsyncCallback's go. Your posts are informative on this topic, so I hope to see more GWT/GXT posts.

Oh, and there's at least one other way of forwarding to a view; Controller has the forwardToView(View, AppEvent) method.

Posted by MarkB on March 14, 2009 at 02:22 AM MDT #

Hi Matt,

this is highly interesting since I am thinking about migrating my Gwt-Ext application to GXT.

Does GXT make it easier to create different view-areas for your application? In a non-ajax-app one constantly sees different screens, becasue the server sends new HTML on every request/navigation flow. In a Gwt-Ext application everything feels very static, since everything needs to be there up front and it feels a little too much like a desktop application. Although everything is very responsive and fast, I does not have a "web"-feel around it.

For example in Gmail, most of the common stuff is in the same view (inbox, trash, etc), but once you hit the settings link, the view changes (you get this yellow tabbed settings panel).

I miss those kind of "flow"-transitions in my Gwt-Ext application, since everything is just there once the app is loaded. You cant navigate away from it without leaving the entire application. It is hard to put all of the functions in this static area, because it is bad for usability.

My problem is not easy to describe, as you have probably felt during reading. The only way to escape this problem traditionally (GWT-only, not Ext-widgets) is to create separate modules for your application, but that means I have to download everything again and again. It wont be as fast as a "single module" that gets loaded once and lets the user navigate inside it.

Posted by Sakuraba on March 14, 2009 at 04:52 AM MDT #

Hey Matt - Have a look at GWTTiger, http://gwtiger.org. It has a pretty robust MVC architecture for GWT that also includes events that fire before and after the page is shown (good for when you dispatch to different pages with passing objects). It biggest asset is the feature of lazy loading your views(screens). The screens/widgets are only instantiated if its used which cuts down on the overhead when the application starts. I have used GWTTiger with GWT-EXT and some several other widgets tools (SmartGWT), so it integrates with just about anything.

Posted by Jeff Genender on March 14, 2009 at 08:18 AM MDT #

Missing com.extjs:gxt:jar:1.2.3 while running mvn com.totsp.gwt:maven-googlewebtoolkit2-plugin:gwt Which repo has that?

Posted by Andreas Andreou on March 14, 2009 at 10:04 PM MDT #

Hi,

we are using GXT since a couple of month.

Because of the irritating features we use the following (simplified) approach:

Only the View talks to the controller via events (handleEvent). This is the case for events which are only interesting in a distinct, logical area. The view is not aware of the concrete type of the controller instance. The controller is responsible for further processing.

The controller talk to his view(s) via direct method calls because of the controller is aware of his view(s).

For "public" events we use the dispatcher mechanism.

We found the GXT mechanism used in GXT sample apps to complicated and irritating.

Of course we implemented more powerfull base Controller classes (extended from GXT Controller) which support "Chain of Responsibility" and so on...

I think our approach is a good compromise in flexibility and nevertheless usability.

Regards

Posted by Martin on March 15, 2009 at 06:01 AM MDT #

Hi to all (and Matt)

Yes I agree, the dispatching mechanism in GXT is not that straightforward and takes some time getting used to.

This is what I feel makes it easy to manage -

  • use Dispatcher - dispatch(...) only from places, where you need global dispatching of events - so the point of entry of handling of events is always going to be the Controller.
  • use Controller - forwardToView(...) when you want the send the event directly to the View(s) which is coupled with the Controller.
  • use View - fireEvent(...) when you want the Controller for that view to handle that event.

Now, on another note - How do you manage Model (in the MVC) for your GXT applications? (I know about the ModelData,BaseModel etc,) I am curious to know general use case scenarios? I will follow up with more questions later.

Posted by AKumar on March 15, 2009 at 01:30 PM MDT #

Man, this archetype could be the solution to my problem described above!

Matt, is the bug, that when pressing "Submit" in the Calendar-View, the history token gets not updated accordingly? Because after I press submit I cannot press on the "Calendar" link anymore, because the new history token will be the same as the old one despite being on the home site and not on the calendar site.

Posted by Sakuraba on March 16, 2009 at 06:04 AM MDT #

@Andreas - You might try changing the version to GXT version 1.2.2. If that doesn't work, installing the 1.2.3 JAR locally should solve your problem.

@Sakuraba - You have correctly identified the bug! The onHistoryChanged() method checks for duplicates and since the calendar history token is a duplicate, it doesn't transition to the next page. I owe you a drink. Please send an e-mail to matt@raibledesigns.com to collect.

Posted by Matt Raible on March 16, 2009 at 12:14 PM MDT #

Just sent you that email, Matt ;)

Posted by Sakuraba on March 16, 2009 at 01:03 PM MDT #

The gwtruts framework seems quite promising.The developer has made an appfuse integration as well. http://apps.sourceforge.net/trac/gwtruts/

Regards,
Matteo

Posted by Matteo on March 18, 2009 at 02:28 AM MDT #

How do you fix this bug? I have an urgent need to fix the bug....

Posted by MAbidi on April 21, 2009 at 09:16 PM MDT #

Matt,

It will be great if you discuss about the data binding and and persistance layers

Regards,
DJ

Posted by DJ on April 25, 2009 at 09:52 AM MDT #

Hi, I just found this post.. I wrote a blog entry "Why Ext-GWT's MVC is broken" (http://blog.gerardin.info/archives/40) which talks about the subject too... Good to see we're not alone..

Posted by Olivier Gérardin on May 04, 2009 at 03:17 PM MDT #

Why do we need classes to implement MVC here? To me, MVC is just a design pattern. And to simplify things, you can combine the view and the controller. No need to decouple this. Then you can write JUnit tests for the model, and use GWT unit tests for View/Controller.

I've just started watching the PureMVC presentation (puremvc.org) after reading the referenced url from Olivier. Man, this framework seems totally overdesigned. Just another level of abstraction you need to understand.

Because the model could be implemented in different ways, it's difficult to abstract that out into a class. If you do, you'll have more overhead (such as PureMVC's proxy classes).

Posted by 188.97.230.73 on June 12, 2009 at 10:52 PM MDT #

I looking for a solution that allows bookmarking of the "application states". I don't see this happen with the GXT MVC.

Posted by Morten Thorsen on June 15, 2009 at 03:35 PM MDT #

@Morten - GWT's History API allows you to implement bookmarking in your application. GXT MVC does integrate with this API, but it can be confusing (hence the reason for this post).

Posted by Matt Raible on June 15, 2009 at 04:13 PM MDT #

"I've been developing a GWT application using a mix of plain ol' GWT and GXT widgets"

Hi Matt,
Can you name a few what widgets you decided to use from GWT, what from GXT? Did you use GXT Layout widgets? I am looking for advice whether I should go with pure GXT widgets or mixing them.
Thanks,

Posted by Brian on August 14, 2009 at 09:37 AM MDT #

@Brian - in the end, we removed GXT in most places. This was because it made our application's JS too big. We were replacing an existing Web 1.0 site, so it had to "pop" when the page first loaded. In my current project, we're building an application that's part of a product (will be hosted on customer's intranet) and we're using GXT. If you're not going to use GXT's look-and-feel (which we didn't on the project referenced in this post), I'd recommend using the out-of-the-box GWT widgets.

Posted by Matt Raible on August 14, 2009 at 02:31 PM MDT #

[Trackback] GWT, czyli Google Web Toolkit to nic innego jak zbiór komponentów, które mo?na u?y? podczas tworzenia aplikacji. GWT jest ?atwe, kod tworzy si? szybko i ?atwo uruchamia chocia?by z poziomu Mavena, jednak?e najwi?kszym problemem nie jest to jak stworzy?...

Posted by The Code-House Blog on November 05, 2009 at 02:16 PM MST #

Hello,

I'm researching on how to apply the internal GXT MVC structure into a GXT desktop application.

I started out integrating the Login dialog from the Maill application (using the MVC structure) into the GXT desktop. The login is already working and upon a successful login, the desktop and shortcuts are displayed.

Now, I have some questions on how to move forward. I hope you can help me out by pointing me to the right direction.

1. I'm just starting out with GXT MVC, and the only guide I have on how to implement it is the GXT mail application sample. To integrate the MVC structure into a a web desktop app, I'm planning to make a Controller and a View that corresponds to a DEsktop Shortcut/window. IS this correct?

Ex:

- My desktop has a shortcut/window called My Machines (A masterlist grid of all the machines, with all machine info and CRUD)

- MachineView -> Constructs the view (grid with CRUD on a window).
- MachineController -> Registers the ShowMachineWindow event. IF the event is dispatched, this controller displays the view MachineView.

This structure is repeated for every shortcut/window in the desktop. IS this how to go about it? OR am I doing it all wrong? What's the best way to do it?

Thanks!

Posted by kurt on January 19, 2010 at 08:17 PM MST #

kurt,
Having a Controller per Window may make sense. Window in the webdesktop really represent applications that run independently to each other. So it is really a Controller per application type. Depending on what the Window does, you could have one to many VIews. It would even be possible to have child Controllers. It really depends on what the Window is doing. A Window could contain something simple, or a Window could represent a complex application.

Hope that helps.

Posted by Darrell Meyer on March 15, 2010 at 07:39 PM MDT #

I am starting with GXT also, but I plan on using MVP, as shown here:

http://www.youtube.com/watch?v=PDuhR18-EdM

and here: http://extgwt-mvp4g-gae.blogspot.com/2009/10/gwt-app-architecture-best-practices.html.

I never understood MVC and have indeed heard a few different explanations of what it is. The MVP pattern seems simpler and better.

Anyone had similar thoughts? Anyone care? um...ok. I'll be leaving now. adios.

Posted by jorel on April 27, 2010 at 11:50 AM MDT #

GXT is not very well suited for MVP, but it doesnt mean it's not feasible.

GXT's MVC is so bad anyway that I would have gone with MVP too if I had to start the project again.

Posted by Olivier on April 28, 2010 at 07:35 AM MDT #

@jorel -> yeh man u are absolutely right, M having the same feeling for MVP , it seems to be simpler and promising aswell.

Posted by Chantu on June 03, 2010 at 12:05 AM MDT #

Actually, GXT MVC works out well for me. I like to use code splitting via controller.

Code splitting with GXT MVC on GAE

Posted by Shawn on July 21, 2010 at 10:20 PM MDT #

Post a Comment:
  • HTML Syntax: Allowed