Insert Element into DOM and receive click events?

39 views
Skip to first unread message

Ben FS

unread,
Apr 21, 2009, 12:50:18 PM4/21/09
to Google Web Toolkit
I'd like to dynamically insert a Widget into/next to a single
TreeItem, whenever a TreeItem is selected, but event handlers on the
Widget never fire when I do this.

My approach so far: I dynamically manipulate the DOM of a single
TreeItem, when a selection event occurs. First I insert a DIV sibling,
and then I insert the Widget into that placeholder. Something like
this:

Button b = new Button("Click me", new ClickHandler() {
public void onClick(ClickEvent event) { Window.alert("I was
clicked!"); }
});

Element itemDiv = treeItem.getElement(); // the TreeItem's underlying
element
Element spanEdit = DOM.createSpan(); // a container, perhaps this
is not necessary
DOM.appendChild(itemDiv, spanEdit);

DOM.appendChild(spanEdit, b.getElement());

The button appears in the TreeItem when the TreeItem is selected, but
I am not able to generate any click events when I try to click on the
button with the mouse. I've also tried replacing the Button with
direct HTML, as follows:

HTML h = new HTML("<a href='javascript:alert();'>Click me for alert</
a>");

Once inserted into the TreeItem, on mouseover the browser status bar
shows the link target, but clicking on it does not generate a popup.

My sense is that I need to do something else when I insert an Element
into the DOM, to ensure that it participates in the event handling
correctly. Yes? What else do I need to do?

Perhaps the Tree's SelectionHandler is interfering - a mousedown on
anything within a tree's node triggers a selection event and no other
events are processed?

Note: This used to work for me, using GWT 1.4.62, but even then only
when the inserted Widget was a Button (for all other Widget's that I
tried, the click event never reached the declared handler).

Note: I would prefer to do all this without manipulating the DOM, but
there is a bug in TreeItem, since early version of GWT, that prohibits
me from dynamically removing and later replacing the TreeItem's
content.
http://code.google.com/p/google-web-toolkit/issues/detail?id=2297

Thanks for any help you can provide!

Sumit Chandel

unread,
Apr 23, 2009, 2:48:03 PM4/23/09
to Google-We...@googlegroups.com
Hi Ben,

Is there any reason why you couldn't just call treeItem.setWidget(b) ? That should change the tree item to the button widget and also properly register the click handlers on the button so that the handler is fired all the way out.

Hope that helps,
-Sumit Chandel

Ben FS

unread,
Apr 23, 2009, 4:12:55 PM4/23/09
to Google Web Toolkit
Hi Sumit,

> Is there any reason why you couldn't just call treeItem.setWidget(b) ?
Yes. See issue #2297 that I submitted one year ago.
"TreeItem.setWidget deletes state/content of the widget that is
replaced "
http://code.google.com/p/google-web-toolkit/issues/detail?id=2297

In short, when you call TreeItem.setWidget, it deletes the content/
state in the DOM of the existing widget. For widgets that only store
their state in the DOM (such as the Label), this is bad
news.

By default, when you supply text data to the Tree, it renders this
text in each TreeItem as a Label. I want to dynamically modify an
individual node (make it editable), and after editing or when a
different node is selected, return the node to the original state.
Let's say I do this:

Widget normal = treeItem.getWidget(); // save this for later
treeItem.setWidget(someEditor);
// do some editing, then later in another event handler
treeItem.setWidget(normal);

The debugger will show that, as soon as setWidget executes, the text
of the original Widget, in variable "normal", has been erased. Refer
to the issue I linked above to see the TreeItem source code that
causes this effect. Again, it only matters for Widgets that store
their state in the DOM (I don't know which these are, but I know it
includes Label).


> That should change the tree item to the button widget and also properly register
> the click handlers on the button so that the handler is fired all the way
> out.
Yes, and this does work. But I want to be able to make the change only
temporary, and return the node to its original state after some time.
I want it to be reversible. I tried various approaches in the past,
and finally got one to work (i.e. appending a Button next to the
existing Widget, but since TreeItem does not have an "append" method,
I directly manipulate the DOM to achieve this effect in a reversable
manner). This approach no longer works in GWT 1.6 - the Button event
handlers no longer run.

Can you suggest a better approach, please? I feel there is probably a
way to achieve this (reversably show an editor control, return to
normal node state afterwards) that is better than what I've tried, but
I have not been able to figure it out on my own ... perhaps a way to
save the previous Widget without having its state modified by the
TreeItem.setWidget call? Is it as simple as cloning/copying that
original Widget?

> Hope that helps,
> -Sumit Chandel
Thank you for taking the time to respond, it is much appreciated.
> > Thanks for any help you can provide!- Hide quoted text -
>
> - Show quoted text -

Sumit Chandel

unread,
Apr 23, 2009, 8:58:03 PM4/23/09
to Google-We...@googlegroups.com
Hi Ben,

Ah, I see what you mean. Sorry for not reading the issue report more carefully the first time around.

It looks like this is only an issue in IE 6/7. possibly IE 8 as well. I reproduced the issue and updated Issue #2297 to see that it gets addressed.

For the moment, simply cloning the original widget and using that clone seems to be the best workaround. You could also try appending the button the way you've been doing before, but it'll take some tinkering around to get it hooked up properly and have the click event reach the handler. If keeping clones around proves to be a problem (for example, having to do this for more than a couple of widgets), let me know and we can dig in deeper on the manual DOM.appendChild() workaround until Issue #2297 gets a fix.

Hope that helps,
-Sumit Chandel

Ben FS

unread,
Apr 24, 2009, 12:36:42 AM4/24/09
to Google Web Toolkit
> Ah, I see what you mean. Sorry for not reading the issue report more
> carefully the first time around.
No problem, thanks for increasing the priority and for testing the
issue across browsers.

> For the moment, simply cloning the original widget and using that clone
> seems to be the best workaround.
I've tried this, but can't get it to work right. First, I don't know
how to make this work in general, because Widget doesn't have a clone
() method. Second, for the various subclasses of Widget that I've
tried, so far all of them lose their "content" when they are removed
from the tree - so I can't just keep a reference.

The only general approach I can think of is to wrap every node in a
panel from the start, so that I can add/remove from that panel as
needed. I'm pretty sure I tried something along these lines a year ago
and found it to be problematic (too "heavy", as I recall).

In my existing code, most of my TreeItem content is HTML, so it should
be possible for me to "clone/copy" just the content as a String,
squirrel it away and, after editing, return the node to its normal
state by inserting a newly instantiated HTML object. I'll try this and
see if I can get it to work - but it precludes me from using anything
other than text or HTML in each node.

> You could also try appending the button the
> way you've been doing before, but it'll take some tinkering around to get it
> hooked up properly and have the click event reach the handler.
I've done a lot of tinkering already, without success. My tree has a
SelectionHandler, and that seems to keep the ClickHandler from
executing when the Button's Element is appended to the DOM directly. I
read the memory leak / cycle / event listener article, and I tried
adding a call to sinkEvent(Event.ONCLICK), but it didn't work. I'm
basically poking around in the dark ... if you can think of a
workaround, I'd like to try it. I think the relevant conditions are: a
Tree with SelectionHandler, OpenHandler, CloseHandler and onSelection
() should dynamically append a Button with a ClickHandler next to the
TreeItem content (similarly, onSelection() should first remove this
Button from any previously selected nodes).

> If keeping
> clones around proves to be a problem (for example, having to do this for
> more than a couple of widgets), let me know and we can dig in deeper on the
> manual DOM.appendChild() workaround until Issue #2297 gets a fix.
>
> Hope that helps,
> -Sumit Chandel
Thanks, you've definitely been a great help.
> > > - Show quoted text -- Hide quoted text -

Ben FS

unread,
Apr 24, 2009, 2:48:54 AM4/24/09
to Google Web Toolkit
> In my existing code, most of my TreeItem content is HTML, so it should
> be possible for me to "clone/copy" just the content as a String,
> squirrel it away and, after editing, return the node to its normal
> state by inserting a newly instantiated HTML object. I'll try this and
> see if I can get it to work - but it precludes me from using anything
> other than text or HTML in each node.
I am now restricting myself to only store textual / markup in each
tree node, which makes this workaround possible and gets my code back
to a working state with GWT 1.6. It's not ideal, and there are some
styling issues, but I'll make do with this for now.

> > You could also try appending the button the
> > way you've been doing before, but it'll take some tinkering around to get it
> > hooked up properly and have the click event reach the handler.
I'm still interested in how to do this, when you have time to give me
some pointers.

Do you know whether the "FastTree", as referenced in the issue
comments, would work better for what I'm trying to do?

Thank you,
Ben.

Vitali Lovich

unread,
Apr 24, 2009, 3:36:26 AM4/24/09
to Google-We...@googlegroups.com
As a workaround, would removing the TreeItem from the parent tree itself work?  It's not a general solution since you'd have to append it to the end of the tree (Tree doesn't appear to support insertion of children into arbitrary positions) to get it back, but it's what the example you gave in the issue does, so maybe it's OK for you?

alex.d

unread,
Apr 24, 2009, 3:40:27 AM4/24/09
to Google Web Toolkit
What about making your treeitem-widget an absolutPanel for example,
put both - your lable and button in it along with a small switch-
function to make only one of the visible at a time. This may cause
some perfomance problems but when it's not that much of three items we
are speaking about, you man not even notice it.

Vitali Lovich

unread,
Apr 24, 2009, 4:01:24 AM4/24/09
to Google-We...@googlegroups.com
Or just put a simple panel.  Then set the widget of the simple panel to whatever you want.  That's actually a great approach alex.  Does that work Ben?
Reply all
Reply to author
Forward
0 new messages