Tuesday, November 2, 2010

GWT table row as UiBinder

Some time ago I wanted to dynamically add rows to a table in GWT, but I wanted to define row template using UiBinder. Programatically it is no problem. You can create FlexTable and add widgets to it. The problem arises when you want to do it using UiBinder. You can create a FlexTable in UiBinder, and you can create widgets, but you can't create element which renders to html tag <tr>. Kazik Pogoda found a way to do it.

First we need two widgets which renter to <tr> and <td>. The code for TR:
public class TrElement extends ComplexPanel {
  private TableRowElement tr;

  public TrElement() {
    Document doc = Document.get();
    tr = doc.createTRElement();
    setElement(tr);
  }

  @Override
  public void add(Widget child) {
    add(child, (Element) tr.cast());
  }
}
The TD is analogous, just change TableRowElement into TableCellElement and doc.createTRElement() into doc.createTDElement(). We can now create UiBinder xml file which renders to single table row (TR element is it's root):
<!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:my="urn:import:pl.my.gwt.client">
 
  <my:TrElement>
    <my:TdElement>
      <g:HTMLPanel>
        <g:Label ui:field="icon" styleName="Icon"></g:Label>
        <g:Label ui:field="title" styleName="Title"></g:Label>
        <g:Label ui:field="description" styleName="Description"></g:Label>
      </g:HTMLPanel>
    </my:TdElement>
    <my:TdElement>
      <g:Label ui:field="price" styleName="Price"></g:Label>
    </my:TdElement>
  </my:TrElement>
</ui:UiBinder>
Here is how we can use it to add to a table (FlexTable):
TableRowView trView = new TableRowView();
table.getElement().appendChild(trView.getElement());