Wednesday, July 20, 2011

Hyperlink Navigation

Building your application navigation with hyperlink can improve user's experience. He can then navigate the same way through your website as he would on a non-ajax website. Hyperlink gives him access to familiar link functionalities like the over state to display the link in the status bar or the right click to open the link in a new tab or copy it.

One feature introduced with Mvp4g-1.3.0 is the hyperlink token generation, which easily creates the token associated to an event. In this tutorial, we're going to modify our previous example to use hyperlinks for our menu. You can download the example here (Project: Mvp4g_Hyperlink_Navigation).

Impact of Hyperlink Navigation

Using hyperlink will impact how you can build your navigation. The first main impact is when you retrieve parameters associated with your navigation. With regular navigation, you get your parameters after the user's action to navigate. The most common case is that you retrieve your parameter in the click handler after the user clicks on your menu.
On the other hand, you build your token for the hyperlink before you display it. You will then need to retrieve your navigation parameters before user's action. With hyperlink token, you will also have to decide when to build your token. Is this token static? Then you can build it once, when you build your hyperlink widget. If not, you may have to build it every time you display it.

The second main impact concerns Mvp4g and how the navigation is going to be treated. When you use regular navigation, you usually fire an event that is forwarded to a handler. With hyperlink navigation, you actually change the history token. This change is handled by the GWT History class that forwards it to the Mvp4g Place Service, which then uses a history converter to fire the appropriate event (which is then forwarded to the handlers). Thus with regular navigation, you only use the event bus whereas with hyperlink navigation, you go through the whole history process. I tried to summarize these differences in the following sequence diagrams:

Sequence Diagram for regular navigation
Sequence Diagram for hyperlink navigation

Changing the event bus to generate token

To generate a token for an event, it is quite easy thanks to the token generation feature introduced in Mvp4g-1.3.0. All you have to do is change the return type of the event method in your event bus interface from void to String. You can generate a token only for events associated with a history converter.

In our example, we need to generate tokens for goToPage1 and goToPage2 events (our place events):
@Events( startView = RootView.class, historyOnStart = true )
public interface HyperlinkNavigationEventBus extends EventBusWithLookup{


    @Event( handlers = Page1Presenter.class, historyConverter = PageHistoryConverter.class, name = "page1", navigationEvent = true )
    String goToPage1( String origin );

    @Event( handlers = Page2Presenter.class, historyConverter = PageHistoryConverter.class, name = "page2", navigationEvent = true )
    String goToPage2( String origin );

To generate the event token, you need to set the event bus in token generation mode by calling the getTokenGenerator method of the presenter. Then you can call your event method. Since the event bus is in token generation mode, this method will return the event token without actually firing the event.
String tokenPage1 = getTokenGenerator().goToPage1( "You clicked the menu." );
When you set the event bus in token generation mode, it will automatically go back to regular mode whenever you call an event method that can generate token (ie an event method that returns a String). If you don't call one of these methods, your event bus will stay in token generation mode.

Implementing hyperlink navigation for our example

For our example, we want to base our navigation on hyperlink. In order to do so, we need to change our menu.

The first thing we need to change is our menu interface. Instead of having the presenter provide two methods to go to other pages, the view will implement two methods to set each page token.
public interface IMenuView extends IsWidget {

    public interface IMenuPresenter {
        //nothing to implement        
    void setPage1Token(String token);
    void setPage2Token(String token);

The next step is to generate the token for the hyperlink. Our tokens are static so we can generate them only once when we bind the view and the presenter.
@Presenter( view = MenuView.class )
public class MenuPresenter extends BasePresenter<IMenuView, HyperlinkNavigationEventBus> implements IMenuPresenter {
    public void bind(){
        String tokenPage1 = getTokenGenerator().goToPage1( "You clicked the menu." );
        view.setPage1Token( tokenPage1 );
        String tokenPage2 = getTokenGenerator().goToPage2( "You clicked the menu." );
        view.setPage2Token( tokenPage2 );

Finally we have to modify our menu view to use hyperlink widgets.
<!DOCTYPE ui:UiBinder SYSTEM "">
<ui:UiBinder xmlns:ui=""
    <g:HTMLPanel styleName="menu">
        <table cellpadding="0" cellspacing="0">
                    <g:Hyperlink ui:field="page1">Page 1</g:Hyperlink>
                    <g:Hyperlink ui:field="page2">Page 2</g:Hyperlink>
We then need to use these hyperlink widgets to set the page token.
public class MenuView extends ReverseCompositeView<IMenuPresenter> implements IMenuView {


    public void setPage1Token( String token ) {
        page1.setTargetHistoryToken( token );    

    public void setPage2Token( String token ) {
        page2.setTargetHistoryToken( token );        

We now have our example with a navigation system based on hyperlink.

What's next?

As you can see, building your application navigation with hyperlink is quite easy thanks to the new feature introduced in Mvp4g-1.3.0. Using hyperlink will greatly improve your user experience but you will have to make sure that the constraints that come with it can work for your project.

In the next post, I will describe another advanced Mvp4g feature to set your own place service.

1 comment:

  1. I updated the example with Mvp4g-1.4.0, the tutorial didn't change.