Fancy UI

All About Crazy IT Stuff

Writing Custom CellRenderer using the Declarative new GWT 2.5 UiRenderer

with 18 comments

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.

Image

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 , ,

18 Responses

Subscribe to comments with RSS.

  1. Reblogged this on Arcbees's developer Blog and commented:
    Must read on GWT CellRenderer.

    Christian Goudreau

    November 26, 2012 at 9:04 pm

  2. Nice writeup!

    branflake2267

    November 26, 2012 at 11:18 pm

  3. 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

  4. 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

  5. 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

  6. 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

  7. Grate example and worked for me…

    Thank you

    Siddarth

    May 10, 2013 at 8:16 am

  8. […] Writing Custom CellRenderer using the Declarative new GWT 2.5 UiRenderer […]

  9. 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

  10. 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

  11. 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

  12. […] 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, […]

  13. […] 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 […]

  14. 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


Leave a reply to branflake2267 Cancel reply