Wednesday, November 3, 2010

Managing history in GWT

Managing history is one of the important task of an AJAX application. The GWT application is mostly a single page and so the developer has to take care of what to do with the forward and back buttons. One easy but not so good step is to take out the toolbar from the browser all together, so that we don’t need to worry about it. A better approach is to preserve the history of the major changes in the application so that they are easily accessible with the back and forward buttons.

To explain more about the history I will be considering a simple login application as most of the examples do. I create a splash screen with a “SignIn” button clicking which will take you to the login page with username and password fields and demonstrate history on it.

  1: package com.snippets.client;
  2: 
  3: import com.google.gwt.core.client.EntryPoint;
  4: import com.google.gwt.event.dom.client.ClickEvent;
  5: import com.google.gwt.event.dom.client.ClickHandler;
  6: import com.google.gwt.event.logical.shared.ValueChangeEvent;
  7: import com.google.gwt.event.logical.shared.ValueChangeHandler;
  8: import com.google.gwt.user.client.History;
  9: import com.google.gwt.user.client.ui.Button;
 10: import com.google.gwt.user.client.ui.Grid;
 11: import com.google.gwt.user.client.ui.Label;
 12: import com.google.gwt.user.client.ui.PasswordTextBox;
 13: import com.google.gwt.user.client.ui.RootPanel;
 14: import com.google.gwt.user.client.ui.TextBox;
 15: import com.google.gwt.user.client.ui.VerticalPanel;
 16: 
 17: public class Snippets implements EntryPoint {
 18: 	private static final String LOGIN_PAGE = "Login";
 19: 	private static final String SPLASH_PAGE = "Splash";
 20: 
 21: 	VerticalPanel verticalPanel ;
 22: 
 23: 	public void onModuleLoad() {
 24: 		verticalPanel  = new VerticalPanel();
 25: 
 26: 		History.addValueChangeHandler(new ValueChangeHandler<String>() {
 27: 
 28: 			@Override
 29: 			public void onValueChange(ValueChangeEvent<String> event) {
 30: 				if (LOGIN_PAGE.equals(event.getValue())) 
 31: 				{
 32: 					loginPage();
 33: 				}
 34: 				else if (SPLASH_PAGE.equals(event.getValue())) 
 35: 				{
 36: 					splashPage();
 37: 				}
 38: 			}
 39: 		});
 40: 		History.newItem(SPLASH_PAGE);
 41: 		RootPanel.get().add(verticalPanel);
 42: 	}
 43: 
 44: 	private void loginPage()
 45: 	{
 46: 		final Grid grid = new Grid(3, 2);
 47: 		final Label userName = new Label("name");
 48: 		final TextBox userBox = new TextBox();
 49: 		final Label passwordLabel = new Label("password");
 50: 		final PasswordTextBox passwordBox = new PasswordTextBox();
 51: 
 52: 		final Button loginButton = new Button("login");
 53: 
 54: 		grid.setWidget(0, 0, userName);
 55: 		grid.setWidget(0, 1, userBox);
 56: 
 57: 		grid.setWidget(1, 0, passwordLabel);
 58: 		grid.setWidget(1, 1, passwordBox);
 59: 
 60: 		grid.setWidget(2, 1, loginButton);
 61: 		verticalPanel.clear();
 62: 		verticalPanel.add(grid);
 63: 	}
 64: 
 65: 	private void splashPage()
 66: 	{
 67: 		final Label message = new Label("Welcome. Please login");
 68: 
 69: 		final Button button = new Button("Take Me to login Page");
 70: 		button.addClickHandler(new ClickHandler() {
 71: 
 72: 			@Override
 73: 			public void onClick(ClickEvent event) {
 74: 				History.newItem(LOGIN_PAGE);			
 75: 			}
 76: 		});
 77: 		verticalPanel.clear();
 78: 		verticalPanel.add(message);
 79: 		verticalPanel.add(button);
 80: 	}
 81: }

Firstly, History is basically a stack. So the item first inserted will be last one to be returned. Each of the state in the history is represented with a particular string that is appended to the URL with a “#” sign.

  1. Initially on page load I am setting up the first history item as in line 40.
  2. On the button click in the first page I am going to the next one, so as the state is changed on the button click I am going to add the new page to the history stack using the newItem method again. Line 74
  3. Finally I am adding a history listener to determine what page should be retrieved when a particular token is pulled out from the stack.

GWT internally uses the “window.location.hash” to get the token and send it to the listener. Its up to the developer to determine what to do when a particular token is encountered.

PS: I never worked on managing history on a large application, so I am not quite sure how it will pan out . But I am willing to work on it if some one is interested.

No comments: