Correct way to sink events on UiBinder Element

215 views
Skip to first unread message

Shaun Tarves

unread,
Aug 15, 2013, 3:59:48 PM8/15/13
to google-we...@googlegroups.com
I am defining several elements via UiBinder. My understanding is these are created as com.google.gwt.dom.client.Element during the createAndBind call.

I would like to add a click handler to one of these elements. Is there any way other than casting those to com.google.gwt.dom.client.Element like this?


@UiField 
Element clickable;

DOM.sinkEvents((com.google.gwt.user.client.Element) clickable, Event.ONCLICK);
DOM.setEventListener((com.google.gwt.user.client.Element) clickable, new EventListener() { 
public void onBrowserEvent(Event event) { 
//TODO: Some code

});

Jens

unread,
Aug 15, 2013, 4:39:30 PM8/15/13
to google-we...@googlegroups.com
These are JavaScriptObjects and you can cast them like you want using Element.cast().

But if you need events then just use a Widget (Label) instead of an Element.

-- J.

Nicolas Weeger

unread,
Aug 15, 2013, 4:24:36 PM8/15/13
to google-we...@googlegroups.com
Hello.

> I am defining several elements via UiBinder. My understanding is these are
> created as com.google.gwt.dom.client.Element during the createAndBind call.


Actually you can have elements of type SpanElement, Button, any class (I
think) you wish as long as you correctly reference them in the ui.xml file.


> I would like to add a click handler to one of these elements. Is there any
> way other than casting those to com.google.gwt.dom.client.Element like
> this?


You can use @the UiHandler annotation, like

public class MyFoo extends Composite {
@UiField Button button;

public MyFoo() {
initWidget(button);
}

@UiHandler("button")
void handleClick(ClickEvent e) {
Window.alert("Hello, AJAX");
}
}


as described on
http://www.gwtproject.org/doc/latest/DevGuideUiBinder.html#Simple_binding



Hope this helps


Regards


Nicolas
signature.asc

Steve C

unread,
Aug 15, 2013, 7:39:14 PM8/15/13
to google-we...@googlegroups.com
It sounds like you're using an HTML-based binder, not a Widget binder, so your createAndBindUi would produce an Element that your class can set as its DOM representation (I usually make my class extend Element - for some reason the Eclipse wizard wants to make it a UiObject).  And, then, as another poster mentioned, you can have SpanElement, DivElement, etc., in the Java class to match what's in the xml. So, you shouldn't have to cast to element, the pieces should already be some sort of Element.

I'm pretty sure @UiHandler won't work for an HTML-based binder, since the Java fields aren't widgets.

I haven't tried your approach for hooking up handlers, but have used a delegating approach - the Java class, as a Widget, can have a regular click handler, which can then look at the target of the event and decide what to do accordingly (like fire off a custom event that represents whatever clicking the element meant).

Thomas Broyer

unread,
Aug 19, 2013, 7:59:30 AM8/19/13
to google-we...@googlegroups.com
Don't do that, you might leak memory on some browsers (aka, do it at your own risks)

Either use widgets or use the event delegation pattern, where your widget listens to events and do one thing or another depending on the event's type and target.
For event delegation, using "uibinder for cells" makes it easier as you can use @UiHandler and let the generator do the routing for you.

Shaun Tarves

unread,
Aug 27, 2013, 11:01:07 AM8/27/13
to google-we...@googlegroups.com
Thomas,

Thanks for the heads up about the leak. How would I use "uibinder for
cells" if I am just creating a standard Composite-based widget?

What would an event delegation path look like at the composite level?
Do I just sink the events on this.getElement() and then check if the
event target is my UiField Element?
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "Google Web Toolkit" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/google-web-toolkit/6bJbRxKmh08/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> google-web-tool...@googlegroups.com.
> To post to this group, send email to google-we...@googlegroups.com.
> Visit this group at http://groups.google.com/group/google-web-toolkit.
> For more options, visit https://groups.google.com/groups/opt_out.

Steve C

unread,
Aug 27, 2013, 11:45:15 AM8/27/13
to google-we...@googlegroups.com
Here's how I've done it for a click on a save button within a binder:  I don't have any call to sinkEvents - I think that's OK because the Widget class does that already (?)

    @UiField
    ButtonElement saveButton;

    // other UiFields

    public HandlerRegistration addSaveHandler(final ClickHandler handler) {
        return addDomHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                if (Element.as(event.getNativeEvent().getEventTarget()) == saveButton)
                    handler.onClick(event);
            }           
        }, ClickEvent.getType());

    }



On Thursday, August 15, 2013 3:59:48 PM UTC-4, Shaun Tarves wrote:

Thomas Broyer

unread,
Aug 27, 2013, 11:55:47 AM8/27/13
to google-we...@googlegroups.com


On Tuesday, August 27, 2013 5:01:07 PM UTC+2, Shaun Tarves wrote:
Thomas,

Thanks for the heads up about the leak. How would I use "uibinder for
cells" if I am just creating a standard Composite-based widget?

Either you compose widgets, or you go low-level and then you can use "uibinder for cells" to work at the element-level.

What would an event delegation path look like at the composite level?
Do I just sink the events on this.getElement() and then check if the
event target is my UiField Element?

Basically, yes (you'd use addDomHandler or override onBrowserEvent though rather than "sink the events on this.getElement()")

With "uibinder for cells" (aka UiRenderer), you'd either build a Cell to use in CellWidget (have a look at TextButton for an example of such widget, even though it doesn't use UiRenderer) or extend Widget. In the latter case, you can render() your element into some root element (say, a <div>) using setInnerHTML, and delegate the widget's onBrowserEvent to the UiRenderer's onBrowserEvent, so it will do the dispatch to the appropriate @UiHandler method. And you can possibly get the inner elements to manipulate them directly.

Shaun Tarves

unread,
Aug 30, 2013, 12:06:35 PM8/30/13
to google-we...@googlegroups.com
Thanks all. The addDomHandler suggestion worked wonderfully for my needs.
Reply all
Reply to author
Forward
0 new messages