tags:

views:

82

answers:

3

I try to generate a dynamically gwt ui. As a result I would get a html fragment like this:

<ol>
<li>MyLabel</li>
<li><input type="text"></li>
</ol>

The Label should be a GWT Label and the input should be a GWT TextBox. How can I achieve this with GWT? I've tried to use the HTMLPanel class, but how can I inject the

<li>

Tags?

I can't use UIBinder, since I would like to dynamically create such fragments as shown above.

+1  A: 

Why not put that fragment in a standalone Widget created via UiBinder? (if you know how the structure will look beforehand and just want to insert MyLabel and a TextBox)
Don't be afraid to split your widgets like this - the GWT Compiler is great at optimizing and UiBinder templates are processed at compile time so there shouldn't be any performance penalty (benchmarking is still strongly recommended - YMMV). I'd even say that it'd be faster then trying to add this structure via the DOM package - with UiBinder, the compiler knows what it's dealing with, with DOM you are basically saying: "I know what I'm doing, don't touch my code!" (at least that's my view on this :)). HTMLPanel could be an alternative, but you'd have to assign an id to every element you want to modify/attach stuff to... :/

Bottom line: use UiBinder for this, that's what it was built for.

Igor Klimer
+2  A: 

You can always do something like:

    Document doc = Document.get();
    final OListElement ol = doc.createOLElement();
    LIElement li = doc.createLIElement();
    li.appendChild((new Label()).getElement());
    ol.appendChild(li);
    li = doc.createLIElement();
    li.appendChild((new TextBox()).getElement());
    ol.appendChild(li);
    panel.add(new Widget() {{
        setElement(ol);
    }});
morisil
Sure, but try to read this code x weeks later (or worse, by another developer) - *nightmare*. The whole idea with GWT was to keep the developer on a "higher" level - without worrying about the DOM (or provide him/her the tools to easily create the DOM, like UiBinder).
Igor Klimer
I totally agree. What I wanted to show is just a technique of achieving desired result. UiBinder is a great tool, but more suitable for general layout/customization than for highly dynamic components which, I assume, are the case here. I wouldn't use such DOM spaghetti in my own code. However wrapping presented technique in reusable Panel component (as hambend has shown) seems quite useful. For example it can be used to create tree of lists which would be quite painful with UiBinder.
morisil
+3  A: 

You should create your own subclass of ComplexPanel. This will give you something that works much the same as a HorizontalPanel or VerticalPanel, only based on list elements rather than table elements. It should look something like this:

public class OListPanel extends ComplexPanel { 
final OListElement ol = Document.get().createOLElement();

public OListPanel() {
    setElement(ol);
}

public void add(Widget w) {
    LIElement li = Document.get().createLIElement();
    ol.appendChild(li);
    add(w, (Element)li.cast());
}

public void insert(Widget w, int beforeIndex) {
    checkIndexBoundsForInsertion(beforeIndex);

    LIElement li = Document.get().createLIElement();
    ol.insertBefore(li, ol.getChild(beforeIndex));
    insert(w, (Element)li.cast(), beforeIndex, false);
}

public boolean remove(Widget w) {
    Element li = DOM.getParent(w.getElement());
    boolean removed = super.remove(w);
    if (removed) {
        ol.removeChild(li);
    }
    return removed;
}
}

I haven't tested that but it's basically right. WRT the markup you posted in your question, this code will produce one slight difference, since GWT labels have their own <div> element:

<ol>
<li><div>MyLabel</div></li>
<li><input type="text"></li>
</ol>

You might prefer InlineLabel, which is based on the less intrusive <span> element.

hambend
Perfect solution for me. Thanks.
flash