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());

6 comments:

TS75 said...

Hi,
Great article. I am new to GWT and I think I want which your code does.

But I could not understand the following lines:
TableRowView trView = new TableRowView();
table.getElement().appendChild(trView.getElement());

I could not find the TableRowView.

Basically what I am looking for is I need to create a flextable using UIBinder and have columns declared in UIBinder XML file. But through activity class (using places and activities) I am populating the body of the flextable with the data I get from the RPC call.

Can you help me here?

Anonymous said...

(Yes, I realize this is an old post, but I've only stumbled upon it today.)

You do not need to create a new subclass of ComplexPanel.

Instead, simply use an HTMLPanel, but which will render to a tr element:

<g:HTMLPanel element="tr">
<td>Something</td>
</g:HTMLPanel>

There you go ! One less class in your project, it's already simpler to understand !

Anonymous said...

Anonymous

I'm new to GWT. Are you saying that by using your approach, that I can dynamically add rows to the HTMLPANEL?

Anonymous said...

does not work for me. Syntactically is working, but that gives a runtime error.

In the above solution, how can you make sure that GWT widgets do not loose their functionality? For me, all the handlers get lost for example.

Anonymous said...

ups, the code was lost somehow... instead of element="tr" you have to use tag="tr"

Unknown said...

Hey Anonymous 29 August, 2012 20:00

Yes it's true, the handler functionality is lost this way.
Instead, you could just write your own CustomTableElement class. (TableElement, doc.createTableElement(), ...)

Then, instead of
table.getElement().appendChild(trView.getElement());

you could just add your TableRowView as a Widget, rather than as an Element:
customTable.add(trView);

and the handlers still work.