Row Table

The RowTable widget is one of two primary ways to do tables in Tessell. The other is CellTables.


RowTable is most appropriate when:


For really simple tables, or really large tables, CellTable is a better choice.


To use RowTable, you create two presenters and three ui.xml files:

While there is just one PagePresenter instance for the top-level page, there will be multiple RowPresenter instances, one for each table row.

This presenter-per-row allows you to easily hook into the row’s widgets and perform per-row business logic (change row styles, make AJAX calls, etc.).

Simple Example

For example, given a page with an employees table, we’d have Page.ui.xml:

<ui:UiBinder ...>
    ... various html ...

    <mpv:RowTable ui:field="employeeTable"/>


<ui:UiBinder ...>
  <gwt:HTMLPanel tag="table">


<ui:UiBinder ...>
  <gwt:HTMLPanel tag="table">
      <td><gwt:InlineLabel ui:field="name"/></td>
      <td><gwt:InlineLabel ui:field="description"/></td>
        <gwt:Anchor ui:field="edit" text="Edit"/>
        <gwt:Anchor ui:field="delete" text="Delete"/>

Tessell’s view generation will turn these into 3 views, IsPageView, IsEmployeeHeaderView, and IsEmployeeRowView.

The PagePresenter fetches the table data, instantiates an inner-class presenter around each row’s data object, and adds the row’s view to the table, e.g.:

public class PagePresenter extends AbstractPresenter<IsPageView> {

  // ... fetch data from server logic ...

  // called when we get data from the server
  private void onData(ArrayList<Employee> employees) {
    // header doesn't have any logic, so add
    // it's view directly to the table

    // now add each row's view, with each row
    // getting it's own presenter
    for (Employee employee : employees) {
      EmployeeRowPresenter p = addPresenter(new EmployeeRowPresenter(employee));

  private class EmployeeRowPresenter extends AbstractPresenter<IsEmployeeRowView> {
    private final Employee employee;

    private EmployeeRowPresenter(Employee employee) {
      this.employee = employee;

    public void onBind() {
      registerHandler(view.edit().addClickHandler(new ClickHandler() {
        public void onClick(ClickEvent event) {
          // do logic

While this example doesn’t do anything fancy, the idea is that the per-row, stateful EmployeeRowPresenter will scale as your table logic becomes more complex.


Testing RowTable works much like regular Tessell stub-based testing.

public class PagePresenterTest {
  final PagePresenter p = bind(new PagePresenter(registry));
  final StubPageView v = (StubPageView) p.getView();

  public void nameIsSet() {
    assertThat(row(0).name.getText(), is("Employee 1"));
    assertThat(row(1).name.getText(), is("Employee 2"));

  public void deleteDoesSomething() {
    // assert whatever happened

  // returns row {@code i} from the page's row table
  private StubEmployeeRowView row(int i) {
    StubRowTable table = (StubRowTable) v.rowTable();
    return (StubEmployeeRowView) table.getRows().get(i);

  private void doDataResult() {
    // do async callback/something that results in
    // PagePresenter.onData being called

Implementation Details

Internally, RowTable adopts each row’s HTMLPanel as a child widget, so GWT events will work. It then steals the HTMLPanel’s first tr element and appends it to the RowTable’s own tbody element.

Granted, having an <gwt:HTMLPanel tag="table"> for each row looks odd (it insinuates that each row is its own table). However, due to the way browsers’ innerHTML works (which HTMLPanel uses), a root tag="tr" does not work. Without the root table tag, the lone tr is invalid markup and all of the HTML gets dropped.