I am new to UiBinder and I try to use a FieldLabel.
I found this post : GXT: UiBinder new instance of a Widget
where the developer uses those markups
<form:FieldLabel text="Text">
<form:Widget>
<form:TextField ui:field="text"/>
</form:Widget>
</form:FieldLabel>
When I do exactly the same, I get the following error :
ERROR: Illegal child <form:Widget> in a text-only context. Perhaps you are trying to use unescaped HTML where text is required, as in a HasText widget?: <form:FieldLabel text='Text'> (:7)
It seems that my version of GXT (3.0.1) does not allow to have a non-text-only child for the FieldLabel markup.
Up to now, the only solution I found to include a FieldLabel is to use
#UiField(provided = true)
Is there a better way to use FieldLabel with UiBinder?
The problem is that you shouldn't capitalize form:widget:
<form:FieldLabel text="Text">
<form:widget>
<form:TextField ui:field="text"/>
</form:widget>
</form:FieldLabel>
In UiBinder, elements with a capital letter represent a real Widget subclass, while lowercase elements are either a regular html dom element, or some modifier for the parent widget tag. We can see that this is not a dom element because of the form: namespace, the same as the parent widget tag (i.e. <form:FieldLabel>).
How this works: The FieldLabel class has a Java method to give it the widget to display - setWidget. This method is decorated with a #UiChild annotation (in its superclass):
#Override
#UiChild(limit = 1, tagname = "widget")
public void setWidget(Widget w) {
//...
This enables you, the UiBinder user, to refer to a tag as widget, and have that method invoked with whatever contents you enter.
Related
I would like to create a custom GWT composite widget that I can later use this way in *.ui.xml using uiBinder (cw is prefix for my custom widgets package):
<cw:CustomPanel>
<cw:header><g:Label>test</g:Label></cw:header>
<cw:content><g:Label>test</g:Label></cw:content>
</cw:CustomPanel>
In short, I would expect that setHeader and setContent methods on my custom widget are called by the framework somehow.
Is that at all possible?
This is what #UiChild is for, see the JavaDoc at http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/uibinder/client/UiChild.html
If you want to keep the method names setHeader and setContent (instead of addHeader and addContent), you'll have to use
#UiChild(tagname = "header")
void setHeader(Widget headerWidget) {
...
}
Create setHeader(String title) and setContent(String content) methods in your widget's Java class. In these methods add text to your header and content panel respectively. Then you can use this widget in Ui:Binder this way:
<cw:CustomPanel header="test" content=test" />
Trying to extend AbsolutePanel, my UiBinder won't allow the <g:at> element which is normally ok for straight AbsolutePanels. How do I make my AbsolutePanel subclass able to use the <g:at> element? And more generally, can I make custom UiBinder keywords for my own custom Widgets like "at", "west", "layer" etc.?
You can use #UiChild to declare special functions in your widgets accessible in UiBinders.
for example,
class MyPanel extends AbsolutePanel {
#UiChild
public void addAt(Widget w, String parameter1, String parameter2) {
....
Then, in your uiBinder, you can say
<custom:MyPanel>
<custom:at parameter1="HI" parameter2="Anything you like!">
<g:AnySingleWidget />
</custom:at>
</custom:MyPanel>
See #UiChild at http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/uibinder/client/UiChild.html
I'm using a GWT library (gwt-openlayers) which allows me to create a map popup containing arbitrary HTML, similar to Google Maps. I need this HTML to contain a GWT Button widget.
I'm creating some HTML elements on-the-fly like this:
Element outerDiv = DOM.createDiv();
outerDiv.getStyle().setOverflow(Overflow.HIDDEN);
outerDiv.getStyle().setWidth(100, Unit.PCT);
outerDiv.appendChild(new HTML(mapPOI.getHtmlDetails()).getElement());
Button popupButton = new Button("View Property");
popupButton.getElement().getStyle().setFloat(com.google.gwt.dom.client.Style.Float.RIGHT);
outerDiv.appendChild(popupButton.getElement());
Then I'm getting the source HTML for these elements by calling
String src = outerDiv.toString();
and inserting this html into my map marker. Now my map marker displays the content ok, including the button. However, the button won't respond to any events! From what I can gather, this is because the buttons onAttach() method is never being called.
Is there a better way to do this?
Thanks,
Jon
~~~~EDIT~~~~
I'm now trying a new way of doing this, which seems to be the accepted method looking at other similar posts.
First I'm creating my div:
String divId = "popup-" + ref;
String innerHTML = "<div id=\"" +divId + "\"></div>";
Then I'm adding this to my map popup and displaying it (which adds it to the DOM). After the popup has been displayed, I'm getting the Element as follows and trying to wrap a HTMLPanel around it:
Element element = Document.get().getElementById(divId);
HTMLPanel popupHTML = HTMLPanel.wrap(element);
My div element is successfully retrieved. However, HTMLPanel.wrap(element); doesn't complete. The reason for this is that wrap(..) calls RootPanel.detachOnWindowClose(Widget widget), which includes the following assertions:
assert !widgetsToDetach.contains(widget) : "detachOnUnload() called twice "
+ "for the same widget";
assert !isElementChildOfWidget(widget.getElement()) : "A widget that has "
+ "an existing parent widget may not be added to the detach list";
I put some breakpoints in and it seems that the 2nd assertion is failing!
Does anybody have any idea why this might be the case? Should failing this assertion really result in a complete failure of the method (no return)?
Your first approach is good, you just need to register onClick event for your button like this:
DOM.sinkEvents(popupButton.getElement(), Event.ONCLICK);
DOM.setEventListener(popupButton.getElement(), new EventListener() {
#Override
public void onBrowserEvent(Event event) {
//implement the logic after click
}
});
I have checked this, it works 100%!
You might try something like
RootPanel.get("idOfYourMapMarker").add(popupButton);
See RootPanel.get()
Unfortunately, RootPanels are AbsolutePanels which aren't so nice for layout but could work if you just have a simple button to add. You could also try RootLayoutPanel which will give you a LayoutPanel (also not so nice when you just want things to flow). You might end up creating a container widget that does the layout for you, and adding that to the RootPanel.
SimplePanel is a DIV. Perhaps that can be used instead?
You added the element, but you have to keep the hierarchy of the actual GWT Widgets too.
I don't see a clean way to do this, but you could use something like jQuery to grab the button by and ID and add a click handler back to it that would call the original click handler.
private static native void registerEvents(String buttonId, MyClass instance)/*-{
var $ = $wnd.$;
//check click
$('#'+buttonId).live('click', function(e) {
e.preventDefault();
instance.#com.package.MyClass::handleButtonClick(Lcom/google/gwt/event/dom/client/ClickEvent;)(null);
});
}-*/;
Call this registerEvents() either in your onAttach or constructor.
I once had a similar problem. You can use the gwt-openlayer's MapWidget as follows:
private MapWidget createMapWidget() {
final MapOptions defaultMapOptions = new MapOptions();
defaultMapOptions.setDisplayProjection(DEFAULT_PROJECTION);
defaultMapOptions.setNumZoomLevels(TOTAL_ZOOM_LEVELS);
MapWidget mapWidget = new MapWidget(MAP_WIDGET_WIDTH, MAP_WIDGET_HEIGHT, defaultMapOptions);
map = mapWidget.getMap();
return mapWidget;
}
And then add it to any panel be it vertical or horizontal.
MapWidget mapWgt = createMapWidget();
VerticalPanel mainPanel = new VerticalPanel();
mainPanel.add(mapWgt);
...
... add whatever you want
...
You can finally add the created Panel(containing the MapWidget and the gwt widget) to the PopupPanel. Also, you should now be able to add handlers to the gwt button.
I've been working with GWT for awhile, I can't find a way to integrate it with a preexisting website which is a real downer. My page content is already generated for me using jsp, like:
<div id='A'></div>
<div id='B'></div>
etc.
there is no way for me to do something like this though:
public void onModuleLoad() {
SimplePanel spA = new SimplePanel(
Document.getElementById("A"));
spA.add(new Label("hello"));
SimplePanel spB = new SimplePanel(
Document.getElementById("B"));
spB.setWidth("200px");
etc ..
}
seems like there's no way to just wrap a pre-existing element. Is this true, or am I missing how to do this? I need be able to wrap a bunch of elements like this, to manipulate them later on. I see TextBox, Button, a few other classes have wrap() methods, however nothing like that exists for elements,
Thanks
There is a way to wrap existing DOM elements, like Label's wrap() method. For example:
Label label = Label.wrap(DOM.getElementById("A"));
label.setText("Foo!");
Other GWT classes can wrap DOM elements too, like Button, and CheckBox using its constructor.
Use HTMLPanel:
class MyPanel extends HTMLPanel {
private SimplePanel a = new SimplePanel();
private SimplePanel b = new SimplePanel();
public MyPanel() {
super("<div id="a"></div><div id="b"></div>);
addAndReplaceElement(a, "a");
addAndReplaceElement(b, "b");
}
}
I'm creating a composite uibinder widget with a Label and a TextBox.
The intented use is:
<x:XTextBox ui:field="fieldName" label="a caption" >
The text to be put in the box.
</x:XTextBox>
I've found how to catch the label with a custom #UiConstructor constructor, I might add another parameter to the constructor, but I would like to know how to get the text from the xml, just like the GWT tag <g:Label>a caption</g:Label> does.
Any help is greatly appreciated.
I've found a possible implementation by looking at the Label widget source code.
The key point is that the composite widget must implement the HasText interface. so in the declaration and in the body:
public class XTextBox extends Composite implements HasText ...
...
#UiField TextBox textBox;
...
public void setText(String text) {
textBox.setText(text);
}
public String getText() {
return textBox.getText();
}
...
Just put the text into another parameter of your widget and have your #UiConstructor take that parameter. That is:
<x:XTextBox ui:field="fieldName" label="a caption"
text="The text to be put in the box." />
Then your XTextBox.java will have this:
#UiField TextBox textBox;
#UiConstructor XTextBox(String label, String text) {
initWidget(uiBinder.createAndBindUi(this));
textBox.setValue(text);
}
Han is right; HasText is what you need to implement. One thing I found handy is to browse the source if you know a Google widget does something you'd like to do also. e.g.
http://www.google.com/codesearch/p?hl=en#A1edwVHBClQ/user/src/com/google/gwt/user/client/ui/Label.java