Writing Custom CellRenderer using the Declarative new GWT 2.5 UiRenderer
Before GWT 2.5, writing a custom CellRenderer to present data in a certain manner was very complicated and very difficult to achieve.
All the custom UI code had to be written inside a Java class that inherits from the AbstractCell class, using HTML strings concatenation, which is a pretty clunky solution. If you want something cleaner you could choose to use the @Template class, but still it is very difficult to write and to maintain.
I always said, if only Google would add in GWT the ability to define the UI of a custom CellRenderer using XML, just like they did with the introduction of UiBinder, and to have the possibility to bind the UI components using the @UiField and to hook event processing using @UiHandler ==> Hooraaahhhh !!!! This dream came true with GWT 2.5, and it is called the UiRenderer.
In this article I’ll show some snippets of codes of a real use case example to explore most of the features brought to us with UiRender. First let’s describe the custom CellRenderer we will implement.
As you can see in the schema, the cell item renderer is composed of a picture, a text and two buttons, one to remove the item and the other one to open a popup for editing data.
To create a custom CellRenderer using UiRenderer we have to create two files, one containing the XML declarative UI code (think of the MyView.ui.xml files), and the other one holds the associated Java view (think of the MyView.java). The two files must have the same name.
Declarative UI code of MyCellRenderer.ui.xml :
One thing to remember, the difference between the UiRenderer and UiBinder is that in UiRenderer you can only use HTML tags. All GWT custom components will not work in here. I hope Google will add this feature in a future release.
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'> <ui:with field='name' type='java.lang.String'/> <ui:with field='image' type='java.lang.String'/> <ui:style> .imageWrapper { float: left; margin-right: 10px; } .imageWrapper img { width: 64px; height: 64px; } .infoWrapper { float: left; } .infoWrapper div span { display: inline-block; marin-right: 5px; text-decoration: underline; cursor: pointer; } </ui:style> <div> <div class="imageWrapper"> <img alt="{name}" src="{image}" /> </div> <div class="infoWrapper"> <h3><ui:text from="{name}"/></h3> <div> <span ui:field="remove">Remove</span> <span ui:field="update">Update</span> </div> </div> <div style="clear: both;"/> </div> </ui:UiBinder>
Custom CellRenderer Java file MyCellRenderer.java :
This file will manage the UI logic, like for example passing the data to be displayed, formatting data (Date conversion, number conversion…), handling events…
In this example, we have two events to handle (the click on Remove and Update buttons). Thanks to UiRenderer, we can use ui:fields and the @UiHandler annotation. There is some other boilerplate code to add, like the onBrowse event handler to make it work (everything is well described in the snippet of code below).
public class MyCellRenderer extends AbstractCell { // This can be compared to UiBinder --> here where all magic is done public interface Renderer extends UiRenderer { void render(SafeHtmlBuilder sb, String name, String image); void onBrowserEvent(MyCellRenderer o, NativeEvent e, Element p, Person n); } private final Renderer uiRenderer; @Inject public MyCellRenderer(final Renderer uiRenderer) { super(BrowserEvents.CLICK); this.uiRenderer = uiRenderer; } @Override public void onBrowserEvent(Context context, Element parent, Person value, NativeEvent event, ValueUpdater<Person> valueUpdater) { uiRenderer.onBrowserEvent(this, event, parent, value); } @Override public void render(Context context, Person value, SafeHtmlBuilder safeHtmlBuilder) { // All data extraction, transformation should be done in here String name = value.getFirstName() + value.getLastName(); String image = value.getImage(); // We directly the uiRenderer and we pass the HtmlBuilder uiRenderer.render(safeHtmlBuilder, name, image); } @UiHandler({"remove"}) void onRemovePersonClicked(ClickEvent event, Element parent, Person value) { Window.alert("Do you want to remove : " + value.getFirstName()); } @UiHandler({"update"}) void onUpdatePersonClicked(ClickEvent event, Element parent, Person value) { //Maybe use the ActionCell.Delegate to process the action elsewhere... Window.alert("Do you want to update : " + value.getFirstName()); } }
Using the new Renderer in a CellList :
Now that we are done writing our custom, sophisticated and good looking CellRenderer (:D), we can use it the same way we used the old legacy Renderer. I added below a small snippet to show you how in case you forget:
public class MyView extends Composite { public interface Binder extends UiBinder<Widget, WebCartView> { } @UiField(provided = true) CellList personList; @Inject public MyView(final Binder uiBinder, final MyCellRenderer myCellRenderer) { personList = new CellList(myCellRenderer); // Same way as using old Renderers .... // Continue what you always do... } }
That’s it for this article, I hope this was useful and will help you build more awesome sophisticated apps without having to write a lot of complicated code. PS: this new UiRenderer can be used with any Cell based GWT widget.
For more details check the following links : http://goo.gl/2fePf (GWT 2.5 UiRenderer official docs ), http://goo.gl/ogR3J (Cell widget docs).
Written by imrabti
November 26, 2012 at 8:39 pm
Posted in GWT
Tagged with Cell Renderer, CellWidget, UiRenderer
18 Responses
Subscribe to comments with RSS.
Reblogged this on Arcbees's developer Blog and commented:
Must read on GWT CellRenderer.
Christian Goudreau
November 26, 2012 at 9:04 pm
Nice writeup!
branflake2267
November 26, 2012 at 11:18 pm
Hi, is it normal I can only use simple html elements inside the renderer.ui.xml? I tried using ui components like Label and Button but it does not seem to work. Thanks
John
November 28, 2012 at 7:26 am
Yes, for now you are limited to HTML elements, GWT widget are more complex and are not supported in UiRenderer, hopefully Google will add this in future release.
imrabti
November 28, 2012 at 7:30 am
Great example. I have been using UiRenderer but having problems accessing the KeyUp and KeyDown events. Any ideas on how to intercept those? For example these never get called:
@UiHandler({“remove”})
void onKeyDownEvent(KeyDownEvent event, Element parent, Person value)
?
Gene Conroy-Jones (@gwtsushi)
December 10, 2012 at 5:00 pm
Hi,
Is it posible to use the CellRenderer of this tutorial with a CellTable (or Data Grid) instead of a CellList ?
Thanks you,
nzaero
January 5, 2013 at 3:41 am
Yes you can reuse them as they are in a CellTable, CellTree or DataGrid.
imrabti
January 5, 2013 at 10:27 pm
Hi,
I am using UiRenderer. Can i know how to set inner html? because my content consists html tag.
shin
January 11, 2013 at 12:30 pm
Grate example and worked for me…
Thank you
Siddarth
May 10, 2013 at 8:16 am
[…] Writing Custom CellRenderer using the Declarative new GWT 2.5 UiRenderer […]
Weekly Link Digest : GWT | Blog MNCC
August 13, 2013 at 3:18 pm
how to use this uirender inside datagrid?
Deny Wola
December 28, 2013 at 9:25 am
You can use it the same way on a DataGrid.
A DataGrid is basically the same as a CellTable with a more flexible layout.
imrabti
December 29, 2013 at 11:20 am
Hi! your article it has been too useful for me. I have one problem. I have tried this example but update and remove events are never called. I do not understand how:
@UiHandler({“remove”})
void onRemovePersonClicked(ClickEvent event, Element parent, Person value) {
Window.alert(“Do you want to remove : ” + value.getFirstName());
}
could be called. Could you explain me it? Thanks a lot!
Javier Arias
April 24, 2014 at 2:42 pm
Hi,
I have a scenario similar like the example. Only thing is when the update is clicked, the first name changes. Im not sure how to access element of abstract from another element.
Ben
November 19, 2014 at 7:30 pm
[…] have created the CellRenderer using UiRenderer in GWT as mentioned at this page Link. Everything is working fine except I just don't know how to how to reset all elements in that list, […]
How to add presenter to UiRenderer in GWT | 我爱源码网
February 26, 2015 at 3:43 am
[…] have created the CellRenderer using UiRenderer in GWT as mentioned at this page Link. Everything is working fine except I just don’t know how to how to reset all elements in that […]
How to add presenter to UiRenderer in GWT | FYTRO SPORTS
February 26, 2015 at 8:07 pm
Great article, but I found that the css wasn’t applied properly. You have to add field=”local” and then add class=”{local.imageWrapper}” for example.
Drew Spencer
June 15, 2015 at 1:53 pm
Yes you are right I’ll fix that and update the article
imrabti
December 23, 2015 at 11:54 am