How to wrap elements under a GWT HTMLPanel - gwt

Let's say I create an HTMLPanel with some HTML like:
<p>
Blah blah <span id='1'>more html... </span>
</p>
Now I want to attach an event handler to the span. I want to see it as an InlineHTML GWT widget. I tried:
HTMLPanel html = new HTMLPanel(stringOfHTML);
parentWidget.add(html);
String id = "1";
Element span = html.getElementById(id);
InlineHTML wid = InlineHTML.wrap(span); // -- error here
html.addAndReplaceElement(wid, id);
The second-to-last line dies with the AssertionError: A widget that has an existing parent widget may not be added to the detach list.
Is there a way to wrap sub elements in a HTMLPanel?
This is GWT 2.4.
Note
After a few comments and answers I realized that I forgot to mention: usually UiBinder is the answer here, but I'm not using it because the input is html text created in another context by non-programmers.

No, not really. You getting this exception because <span> element is already a part of some widget. wrap methods can be used only to create widgets on top of elements which are not part of some other widget. If you want to handle clicks on this span, you can add dom handler to the HTMLPanel, and then detect which element was clicked.

Convert your <span> into an InlineLabel inside your UiBinder template and attach anything you want to it :).

Related

GWT : How to remove element from it's outermost?

I have one Anchor widget as
<td class="GAS3MDBHJ">
<div class="GAS3MDBJJ">
<a class="gwt-Anchor" href="#export">Export</a>
</div>
</td>
I would like to remove this anchor element from it's root. How can I achieve it.
If I use widget.getParentElement() , I need to write as ...
myanchor.getElement().getParentElement().getParentElement().removeFromParent();
Now it is in third level.If my widget is in level 7 or 8 or 9 , am I need to write getParentElement() repeatedly ?
Has there anyway for fast code ?
I don't want to get it's parent element, I really want to get was outermost element.
You should simply call
anchor.removeFromParent();
It will remove the entire anchor element with all of its inner HTML. The result will be exactly the same if you call
anchor.getElement().removeFromParent();
because anchor.getElement() will give you the outer most element of this widget, just as you wanted.
If you start calling getParentElement(), you will remove more than your anchor widget.

GWT : A widget that has an existing parent widget may not be added to the detach list

This code in GWT (Sidebar is a custom that build a sidear) :
HTML html = new HTML("
<div id=\"container\">some stuff</div>"
);
RootPanel.get("container").add(new Sidebar());
... give that error :
java.lang.AssertionError: A widget that has an existing parent widget may not be added to the detach list
at com.google.gwt.user.client.ui.RootPanel.detachOnWindowClose(RootPanel.java:136)
at com.google.gwt.user.client.ui.RootPanel.get(RootPanel.java:211)
Can you helpplease. I have seen many explanations but nothing help me.
thanks +
I won't delve into explanations, as you say you read them already: enough to say this is an unsupported pattern.
In your case, you'll want to use an HTMLPanel instead of HTML widget, and use the HTMLPanel's add(Widget,String) method to put the Sidebar into the container element:
HTMLPanel html = new HTMLPanel("<div id='container'>some stuff</div>");
html.add(new Sidebar(), "container");

How can I create a contenteditable <div> in GWT on the client side?

I'm trying to create a custom widget in GWT that creates a div with contenteditable=true inside of it. The problem is that when I create this div and I initialize this widget, the div does not have the contenteditable property.
my code:
public MyWidget(){
FlowPanel panel = new FlowPanel();
initWidget(panel);
HTML div = new HTML("<div id=\"my-div\" contenteditable=true></div>");
div.setText("hello there");
div.addHandler(new MyWidgetKeyDownHandler(), KeyDownEvent.getType());
mDiv = div;
panel.add(div);
}
But when I run the code and I inspect the source, I see this:
<div>
<div class="gwt-HTML">hello there</div>
</div>
So it looks like it's missing the contenteditable tag as well as the id. What am I doing wrong here? How can I create this contenteditable div widget?
div.getElement().setAttribute('contenteditable', 'true');
I would work around your requirement for a specific id. You can set one with ensureDebugId but you might find it simpler to do without it.

How to replace element with my GWT widget?

Is it possible to replace known html element with my widget component? (Emphasis on the word 'replace', I don't want to put the widget in that element. :)
<body>
<img />
<div />
<a id="tmpEl" />
...
<img />
</body>
would become
<body>
<img />
<div />
<div class="gwt-panel">...</div>
...
<img />
</body>
I tried something like this...
tmpEl.getParentElement().replaceChild(myPanel.getElement(), tmpEl);
...but the resulting DOM elements were 'deaf', i.e. they did not receive click events. (To make this work I would probably have to call RootPanel.get().adopt(widget), but that method is not accessible.)
For a second I thought HTMLPanel.addAndReplaceElement could be the answer, but that only works when your 'placeholder' element is (direct) child of HTMLPanel widget. Which is obviously not my case. :(
Note please that I only know id of that element, I'm not creating it. Simply put: I need exactly what the question says.
As for 'DOM manipulation at higher level': I will happily manipulate the DOM at highest possible level if it lets me place widget instead of that placeholder element.
It seems that calling widget.onAttach() after inserting widget into DOM does the trick.
class MyWidget extends Composite
{
...
public void attach()
{
/* Widget.onAttach() is protected
*/
onAttach();
/* mandatory for all widgets without parent widget
*/
RootPanel.detachOnWindowClose(this);
}
}
tmpEl.getParentElement().replaceChild(myWidget.getElement(), tmpEl);
myWidget.attach();
Credit goes to André at Google Web Toolkit group.
I still wonder though why there is no RootPanel.addAndReplaceElement(Widget, Element), similar to HTMLPanel.addAndReplaceElement(Widget, Element).
The solution is probably not so much different from what Igor suggested. I'd write something like this:
RootPanel rootPanel = RootPanel.get();
Element anchorElement = DOM.getElementById("tmpEl");
Anchor anchor = Anchor.wrap(anchorElement);
rootPanel.remove(anchor);
rootPanel.insert(new HTML("<div class='gwt-panel'>...</div>", 0);
I agree with markovuksanovic - you should consider DOM manipulation on a "higher level". For example, the functionality you need is provided via the InsertPanel interface, which FlowPanel implements:
FlowPanel mainPanel = new FlowPanel();
Hyperlink link = new Hyperlink("Something cool");
mainPanel.add(link);
mainPanel.add(new Label("Bla bla"));
// Now we want to replace the first element of the FlowPanel with a TextBox
// We can do that by its index...
mainPanel.remove(0);
// ...or Widget instance
mainPanel.remove(link);
// Now we add a TextBox at the beginning
mainPanel.add(new TextBox(), 0);
As you can see, this code is much more readable (at least to me), you don't manipulate the DOM directly (referencing via ids and such). Of course, there are places where direct DOM manipulation is beneficial (optimizing, most notably), but for the most part, I'd avoid juggling Elements, ids and such :) (at least in GWT)
I'm doing something pretty similar. I'm reading the contents of a <div>; using the elements found in the <div> to build an animated menu which then replaces the original content. The animated menu is a widget.
It seems to work...
// DisclosurePanel is a widget
DisclosurePanel accordion_panel = processAccordion(accordionElement);
// accordionElement is found in the DOM (it's a com.google.gwt.user.client.Element)
// clear what was there
accordionElement.setInnerText("");
// add the widget in
RootPanel.get(accordionElement.getId()).add(accordion_panel);
I would suggest you try something like this...
<body>
<a id="tmpEl" />
</body>
then in somewhere create a widget (e.g. textBox widget)
TextBox tb = new TextBox();
After you have created the widget you can get it's DOM object by using tb.getElement() (I'm not sure that's the correct method name, but it's definitely something like getElement)
After that you could use
Element parent = Document.getElementById('tmpEl').getParent();
parent.removeChild(Document.getElementById('tmpEl'));
parent.appendChild(tb.getElement());
One more thing that add() does is call Widget.onAttach() on the widget that is being added to the panel. onAttach does some work to register the widget to receive events.
You could try calling tb.onAttach(); It might also be necessary to call RootPanel.detachOnWindowClose(tb); (as mentioned in a previous post)

GWT page layout practices

I am making a GWT app based off of an HTML mockup. The mockup has about 4 or 5 different layouts made with divs and css. Right now I have one HTML page with just the basic elements of my layout (header, body, footer). The other layouts are the same thing, with different layouts for the body (i.e. two column, three column). I attempted to add the extra markup the the base template using the following code:
RootPanel.get("main_area").add(html);
Where main_area is the ID of my body div and html is an HTML object with the additional divs for the column layout.
This works fine, but when I try to add some text (or anything) to the divs I added:
RootPanel.get("left_column").add(new Label("test"));
I get the following error:
java.lang.AssertionError: A widget that has an existing parent widget may not be added to the detach list
at com.google.gwt.user.client.ui.RootPanel.detachOnWindowClose(RootPanel.java:122)
at com.google.gwt.user.client.ui.RootPanel.get(RootPanel.java:197)
I assume that I'm going about this completely wrong, but I have no idea what the correct way of doing this would be.
You may want to look into HTMLPanel.
i.e.
HTMLPanel hpanel = new HTMLPanel("<div id='morehtml'></div>");
hpanel.add(new Label("Hello, I am inside morehtml"), "morehtml");
RootPanel.get("main_area").add(hpanel);
I usually have an div which is the entry point and then I build all my GWT layout from that, e.g. ( not checked in IDE):
Panel root = RootPanel.get("entryPoint");
VerticalPanel rows = new VerticalPanel();
rows.add(new Label("Row 1"));
rows.add(new Label("Row 2"));
root.add(contents);