Developing a GWT TodoMVC application

This blog post describes my experiences of developing a simple Todo application with Google Web Toolkit (GWT), that I have contributed to the JavaScript TodoMVC project, which compares the implementation of the same application with various JavaScript frameworks. This blog discusses why I chose GWT, the compromises and benefits of this approach.

When I started writing this blog a few years ago I mostly focused on WPF and Silverlight technologies. More recently I have found the need to diversify and have invested a lot of time and energy into learning JavaScript, readying myself for the HTML5 revolution that seems to be happening around us! (even though I think the revolution is happening a bit to quickly).

One obstacle developers often face when starting to learn JavaScript is the vast number of mature JavaScript frameworks that can be found on the internet. When selecting a JavaScript framework for DOM manipulation and animation, jQuery has now become the de-facto standard. Whereas, when it comes to selecting a framework for structuring your application logic and implementing suitable UI design patterns, there are numerous seemingly viable alternatives, and it is very hard to know which to choose.

To assist in framework selection, Addy Osmani created the TodoMVC project which implements the same, simple Todo-list application with a wide range of JavaScript frameworks (18 to date!).

This project has been described as JavaScript framework 'speed dating', in that it allows an easy comparison of a diverse range of frameworks within a relatively short period of time. Whilst the simple Todo application doesn't have the depth required to fully explore each framework in detail, nor does it help answer other important questions regarding support, documentation and licensing, what it does do very well (and very quickly) is give you a 'feel' for each framework.

Recently myself and Scott Logic's very own JavaScript guru, Chris Price, gave a brief presentation to a new client on JavaScript framework selection. We were both aware of the TodoMVC project, but the frameworks we wanted to demonstrate, Google Closure and Google Web Toolkit (GWT), were lacking examples. This is something we set about fixing. Chris completed his TodoMVC Closure port a couple of weeks ago, and I have just finished the GWT version, which you can see online at github (the GWT version has been reviewed in detail and will be included in the next release).

The rest of this blog post describes the GWT implementation.

Why GWT?

When compared with the other JavaScript frameworks in the TodoMVC project, GWT is different ... very different. With GWT you write your application in Java, which is compiled into JavaScript by the GWT compiler. The reason I am interested in GWT is that (in my opinion) JavaScript has some pretty big limitations that hamper its use when creating large-scale enterprise applications, a topic I have touched on a few times before. This is not to say I dislike JavaScript, quite the contrary, it is just that there are some problems that strongly typed languages are better at solving.

GWT is quite an extensive framework, whilst it is not on a par with the likes of WinForms or WPF in terms of controls, libraries and framework features, you do get a lot of 'stuff' for free. But what I really like about GWT is not so much the high-level abstraction that it provides, yes ... you can use GWT without knowing the first thing about the DOM or web browsers, but the fact that it does not prohibit you from working with the DOM in the same way that you would with any other JavaScript framework. If you strip away all the widgets, event bus, ui-binder and the rest, you are left with nothing more than a trimmed-down Java SE library and the DOM.

The GWT Todo application

My implementation of the TodoMVC application uses the Model View Presenter (MVP) pattern, as described in the 'Large scale app development' papers published by Google. This pattern is quite effective for GWT development; in that it promotes a Humble View (as described by Martin Fowler), which makes testing your GWT application much faster (i.e. no compilation to JavaScript is required to unit test)

My implementation of the Todo application is nothing notable, just MVP-by-numbers as illustrated by the UML class diagram below:

Very briefly ... the ToDoPresenter manages a collection of ToDoItem instances, this includes create, update, delete and persistence. The presenter exposes two interfaces, ToDoPresenter.View, which is the interface that a view is expected to implement, and ToDoPresenter.ViewEventHandler, which is an interface that handles view 'events'. Each ToDoItem instance has a reference back to the presenter so that it can remove itself and notify the presenter of state changes (yes, I wish Java had events and INotifyPropertyChanged).

The view is implemented declaratively via the GWT UiBinder. The markup for the view is shown below:

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
  xmlns:g="urn:import:com.google.gwt.user.client.ui"
  xmlns:cv="urn:import:com.google.gwt.user.cellview.client"
  xmlns:todo="urn:import:com.todo.client">
  <g:HTMLPanel>
    <div id="todoapp">
      <header>
        <h1>Todos</h1>
        <todo:TextBoxWithPlaceholder
          placeholder="What needs to be done?" ui:field="taskText">
        </todo:TextBoxWithPlaceholder>
      </header>

      <section ui:field="mainSection">
        <g:CheckBox ui:field="toggleAllCheckBox">Mark all as complete</g:CheckBox>
        <div id="todo-list">
          <cv:CellList ui:field="todoTable"></cv:CellList>
        </div>
      </section>

      <footer ui:field="todoStatsContainer">
        <g:Anchor href="#" ui:field="clearCompleted">
          Clear
          <span class="number-done" ui:field="clearTasksCount"></span>
          completed
          <span class="word-done" ui:field="clearTasksLabel"></span>
        </g:Anchor>
        <div id="todo-count">
          <span class="number" ui:field="remainingTasksCount"></span>
          <span class="word" ui:field="remainingTasksLabel"></span>
          left.
        </div>
      </footer>
    </div>

    <div id="instructions">
      Double-click to edit a todo.
    </div>

    <div id="credits">
      Created by
      <br />
      <a href="http://jgn.me/">J&eacute;r&ocirc;me Gravel-Niquet</a>
      <br />
      Modified to use
      <a href="http://code.google.com/webtoolkit/">Google Web Toolkit</a>
      by
      <a href="http://www.scottlogic.co.uk/blog/colin/">Colin Eberhardt</a>
    </div>
  </g:HTMLPanel>
</ui:UiBinder> 

This closely mirrors the standard TodoMVC template.

Todo Item Rendering

The most interesting part of the application is the way that the list of Todo items is rendered. GWT has a number of framework features that support the management of lists of data, and for this application I opted to use a Cell Widget, which is a common set of interfaces that expose and render list like data, automatically updating the UI as data is added / removed.

In the TodoMVC application the data is presented as an AbstractDataProvider which is coupled to a CellList view component. Unfortunately, this is where I started to hit a few problems. The TodoMVC project supplies a standard template that all implementations should follow. Within the template the list of Todo items are rendered as an unordered list (ul / li). However, the GWT CellList uses a div as the root container for list items. Furthermore, each rendered list item is also wrapped in a div. There is no obvious way to change this functionality without re-creating the entire CellList widget and unfortunately the target HTML output could not be achieved. As a result of this, I had to modify quite a bit of the application styling to target the different structure.

The GWT Cell Widgets have a number of standard cell types, including checkbox cells, text input cells etc ... however, this application required quite a specialised cell, including both a checkbox and a text field, plus an edit mode which replaces the contents with an input field. To support this I implemented a ToDoCell, which is a cell specifically designed for rendering ToDoItem instances.

This cell contains two different templates, one for edit mode, the other for read-only mode:

/**
 * The HTML templates used to render the cell.
 */
interface Templates extends SafeHtmlTemplates {    

  /**
   * The view-mode template
   */
  @SafeHtmlTemplates.Template(
      "<div class='{2}' data-timestamp='{3}'>" +
            "{0} " +
            "<label>{1}</label>" +
            "<a class='destroy'></a>" +
      "</div>")
  SafeHtml view(SafeHtml checked, SafeHtml task, String done, String timestamp);
   
  /**
   * The edit-mode template
   */
  @SafeHtmlTemplates.Template("<div class='listItem editing'><input class='edit' value='{0}' type='text'></div>")
  SafeHtml edit(String task);
}

With the render method picking one or the other template based on whether the current cell is being edited:

@Override  
public void render(Context context, ToDoItem value, SafeHtmlBuilder sb) {
  // render the cell in edit or view mode
  if (isEditing(value)) {
    SafeHtml rendered = templates.edit(value.getTitle());
    sb.append(rendered);
  } else {
    SafeHtml rendered = templates.view(
            SafeHtmlUtils.fromString(value.getTitle()),
            value.isDone() ? "listItem view done" : "listItem view"
    sb.append(rendered);
  }
}

NOTE: The cell widget framework only creates a single instance of each cell, one for each column (for table widgets). Hence the row context information, in this case the ToDoItem, is passed in to all methods that require the row state.

The bulk of the code within this cell implementation sits within the onBrowserEvent method. DOM events are passed to this method, together with the cell's parent element and item being rendered. This allows you to handle keyboard, mouse and other interactions, swapping between edit and view mode etc ...

Within this method we manage the edit process, with commitEdit and endEdit switching between the two different cell templates:

@Override
public void onBrowserEvent(Context context, Element parent, ToDoItem value, NativeEvent event,
    ValueUpdater<ToDoItem> valueUpdater) {

  String type = event.getType();

  if (isEditing(value)) {

    // handle keyup events
  if ("keyup".equals(type)) {
    int keyCode = event.getKeyCode();

    // handle enter key to commit the edit
    if (keyCode == KeyCodes.KEY_ENTER) {          
      commitEdit(parent, value);
      endEdit(context, parent, value);
    }

    // handle escape key to cancel the edit
    if (keyCode == KeyCodes.KEY_ESCAPE) {
      endEdit(context, parent, value);
    }
  }

  // handle blur event
  if ("blur".equals(type) && !beginningEdit) {
    commitEdit(parent, value);
    endEdit(context, parent, value);
  }

} else {
	
	// handle double clicks to enter edit more
	if ("dblclick".equals(type)) { 
    beginEdit(context, parent, value);

    beginningEdit = true;
    InputElement input = getInputElement(parent);
    input.focus();
    input.select();
    beginningEdit = false;
	}

  // when not in edit mode - handle click events on the cell
  if ("click".equals(type)) {

    EventTarget eventTarget = event.getEventTarget();
    Element clickedElement = Element.as(eventTarget);
    String tagName = clickedElement.getTagName();

    // check whether the checkbox was clicked        
    if (tagName.equals("INPUT")) {

      // if so, synchronise the model state
      InputElement input = clickedElement.cast();
      value.setDone(input.isChecked());
      
      // update the 'row' style
      if (input.isChecked()) {
        getViewRootElement(parent).addClassName("done");
      } else {
        getViewRootElement(parent).removeClassName("done");  
      }

    } else if (tagName.equals("A")) {          
      // if the delete anchor was clicked - delete the item
      value.delete();          
    } 
  }
}

As a result, even though the markup differs slightly from the template, the desired functionality is the same.

Conclusions

I think the GWT implementation of the TodoMVC application stands up very well in comparison to the other frameworks presented there. Although, compromises in the output markup did have to be made. I think this is a reflection of the different approach that a typical GWT application development would take, where the application is designed at a higher level, in terms of panels and widgets, rather than at the markup / detail level.

Despite this, the GWT developer does have full access to the DOM, and as a result, I was able to precisely match the functionality required with little effort, even though the GWT framework itself does not support such a specialised cell type as the one required.

It is worth noting that one of the greatest strengths of GWT is not that it means you don't have to understand JavaScript. Rather, it is that you are developing using a strongly-typed language. As a result, when one of the TodoMVC project reviewers asked for name changes, and other refactoring tasks, I was able to make these changes with complete confidence via the Eclipse refactoring tools.

Hopefully other people will find this to be a useful addition to TodoMVC project!

Finally, thanks to Sindre Sorhus and Chris Price for providing detailed review comments on my GWT implementation.

Regards, Colin E.

blog comments powered by Disqus