Is it possible to reuse widgets defined on Uibinder
example:
<g:SuggestBox ui:field='searchBox' />
I mean using the same SuggestBox in two different places.
if it is possible how can I do the call or what ever ?
Thanks for help.
You can do that, here is an example:
Define a widget you want to reuse:
ExampleLabel.java:
package com.example.client;
import import com.google.gwt.user.client.ui.Label;
public class ExampleLabel extends Composite {
interface ExampleLabelBinder extends UiBinder<Widget, ExampleLabel>{}
private static ExampleLabelBinder binder=GWT.create(ExampleLabelBinder.class);
public ExampleLabel() {
initWidget(binder.createAndBindUi(this);
}
}
ExampleLabel.ui.xml
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<g:Label>Just some text</g:Label>
</ui:UiBinder>
To use it you do something like this:
UseExampleLabel.ui.xml:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:myWidgets='urn:import:com.example.client>
<g:FlowPanel>
<myWidgets:ExampleLabel></myWidgets:ExampleLabel>
<myWidgets:ExampleLabel></myWidgets:ExampleLabel>
<myWidgets:ExampleLabel></myWidgets:ExampleLabel>
</g:FlowPanel>
</ui:UiBinder>
The third line points to the package your widgets is in you want to reuse.
Related
I am fitting with UiBinder in gwt. I am using collapse uibinder (bootstrap library). I have the follow code:
<b:Collapse b:id="toggle1" existTrigger="true" ui:field="toggle1">
<b:FluidRow>
<b:Column size="12">
<b:Alert close="false" animation="true" heading="Cabecera">
Text
</b:Alert>
</b:Column>
</b:FluidRow>
</b:Collapse>
My problem is I need change the b:id="toggle1" when I create it. I need use variable. Could someone explain me how to do it? I have looking on internet but I did not find a good explanation
Thank you very mucho in advice.
Set ID in JAVA after calling createAndBindUi().
collapseWidget.getElement().setId("toggle2");
Steps to follow:
Add below entry in you gwt.xml
<inherits name="com.google.gwt.user.Debug"/>
Use debugId along with ui:field as shown below in your ui.xml
<gwt:CheckBox ui:field="myCheckBox" debugId="myCheckBox" />
Now you can get the Id
myCheckBox.getElement().getId();
All the Ids are generated with default prefix gwt-debug- as shown below. If you want then you can remove it.
gwt-debug-myCheckBox
Use any one getElement().setId() or ensureDebugId(). The difference between them is prefixing with gwt-debug-. ensureDebugId() uses prefix.
Sample code: (Setting ID of cancelButton dynamically)
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.uibinder.client.UiTemplate;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.Widget;
public class MyDialogbox extends DialogBox {
private static MyUiBinder myUIBinder = GWT.create(MyUiBinder.class);
#UiTemplate("MyDialogbox.ui.xml")
interface MyUiBinder extends UiBinder<Widget, MyDialogbox> {
}
public MyDialogbox() {
setWidget(myUIBinder.createAndBindUi(this));
System.out.println(cancelButton.getElement().getId());
cancelButton.getElement().setId("cancel");
}
#UiField
Button cancelButton;
#UiHandler("cancelButton")
void doOpenDialogBox(ClickEvent event) {
hide();
}
}
MyDialogbox.ui.xml
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<g:DialogBox autoHide="true" modal="false">
<g:caption>
<b>Caption text</b>
</g:caption>
<g:HTMLPanel>
Body text
<g:Button ui:field='cancelButton' debugId='cancelButton'>Cancel</g:Button>
<g:Button ui:field='okButton' debugId='okButton'>Okay</g:Button>
</g:HTMLPanel>
</g:DialogBox>
</ui:UiBinder>
UiBinder is used to lay out GWT components in a declarative way, with XML markup, as opposed to programmatically, with Java code.
A new XML element in a UiBinder tree means a new instance of that class should be created. Thus, this example from the GWT docs instantiates a new HorizontalPanel and two Labels:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<g:HorizontalPanel>
<g:Label>Keep your ducks</g:Label>
<g:Label>in a row</g:Label>
</g:HorizontalPanel>
</ui:UiBinder>
There's also this other example, with a DockLayoutPanel:
<g:DockLayoutPanel unit='EM'>
<g:north size='5'>
<g:Label>Top</g:Label>
</g:north>
<g:center>
<g:Label>Body</g:Label>
</g:center>
<g:west size='10'>
<g:HTML>
<ul>
<li>Sidebar</li>
<li>Sidebar</li>
<li>Sidebar</li>
</ul>
</g:HTML>
</g:west>
</g:DockLayoutPanel>
In this case, the elements are 'north', 'west', 'center', but those are not new instances of classes, but a configuration of the new DockLayoutPanel.
How do I write a component that, like DockLayoutPanel, accepts custom UiBinder XML elements ?
Where in the source of class DockLayoutPanel, or in its configuration files, is it marked as using special markup, and what to do with the inner content of the special markup elements ?
What other widgets accept special UiBinder markup ?
Seems like you'll have to introduce a custom UiBinder parser for your custom widget.
There's the com.google.gwt.uibinder.elementparsers.DockLayoutPanelParser class which has the following static final map defined:
private static final Map<String, String> DOCK_NAMES = new HashMap<String, String>();
static {
DOCK_NAMES.put("north", "addNorth");
DOCK_NAMES.put("south", "addSouth");
DOCK_NAMES.put("east", "addEast");
DOCK_NAMES.put("west", "addWest");
DOCK_NAMES.put("lineStart", "addLineStart");
DOCK_NAMES.put("lineEnd", "addLineEnd");
DOCK_NAMES.put("center", "add");
}
Haven't searched for all of them but am guessing that any widget that has a custom parser like DockLayoutPanel can process whichever inner XML elements you program it to process.
I'm using Eclipse 3.7, GWT 2.5, Java 1.6, and the latest GPE. I've used UiBinder quite a bit, and now we're looking into using GWT Designer for the next version of our app. I created a basic web app project and let it generate its sample code. Then did New->GWT Designer->GWT UiBinder->Dialog Box. Then I added a button to spawn the popup, and a size and title for the dialog. Here's the widget code:
public class TestPopup extends DialogBox {
private static final Binder binder = GWT.create(Binder.class);
#UiField FlowPanel flowPanel;
interface Binder extends UiBinder<Widget, TestPopup> {
}
public TestPopup() {
setWidget(binder.createAndBindUi(this));
setTitle("Test Popup Title");
setPixelSize(400, 300);
}
}
and the corresponding *ui.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:style>
.panel {
padding: 5px;
border: 5px solid cornflowerblue;
background-color: Menu;
}
</ui:style>
<g:FlowPanel styleName="{style.panel}" ui:field="flowPanel" width="100%" height="100%"/>
</ui:UiBinder>
and this is the result. Can anyone explain how these tools can hack a simple configuration into this:
This is a known issue. The DecoratorPanel and DecoratedPopupPanel Widgets have problems like this when you attempt to set their size specifically. Don't specify the size of the DialogBox. Instead, specify the size of the DialogBox's child Widget and the DialogBox should match it fine.
I just created widget:
public class myWidget<T> extends FlowPanel {
private T value;
public T getValue()
{
return value;
}
public myWidget(T[] values) {
for (T value : values)
{
//do action
}
}
How can I add it using UiBinder? Is it possible at all?
Yes you can. You have to import the package which contains the myWidget class into an XML namespace. Say your package is called com.test.widgets, the declarative layout looks like this:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:my='urn:import:com.test.widgets'>
<my:myWidget>
<g:Label>A label</g:Label>
<g:Label>A second label</g:Label>
</my:myWidget>
</ui:UiBinder>
Note the import xmlns:my='urn:import:com.test.widgets' and the usage <my:myWidget>.
To have your widget usable in Uibinder it must implement at least IsWidget interface. Being a widget already, it of course already implements IsWidget.
Therefore, any non-widget could also be used as a child widget element in uibinder by having it implement IsWidget.
The IsWidget interface requires the non-widget to implement the method asWidget(). Therefore, such a non-widget would have to act as a widget container.
Implementing IsWidget will only allow the class to be used as a child widget element.
Let's say your class is
com.zzz.client.ui.HelloKitty
In order for it be able to have child widget elements, it must implement HasWidgets.
<ui:UiBinder
xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:z='urn:import:com.zzz.client.ui'>
<g:VerticalPanel>
<z:HelloKitty>
<g:button ..../>
<g:textbox>asdf</g:textbox>
</z:HelloKitty>
<g:VerticalPanel>
</ui:UiBinder>
Or, it could also just implement HasOneWidget.
In order to allow the class to have text between its uibinder tags, it must implement HasText.
<ui:UiBinder
xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:z='urn:import:com.zzz.client.ui'>
<g:VerticalPanel>
<z:HelloKitty>qwerty</z:HelloKitty>
<g:VerticalPanel>
</ui:UiBinder>
In order to accept valid HTML between its tags, I believe you should have it implement HasHTML.
None of the answers seem to focus on the generic part. As mentioned by others, you can easily add a generic widget in an UiBinder template by omitting the generic types:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:my='urn:import:com.test.widgets'>
<my:myWidget />
</ui:UiBinder>
But, what about if you want to reference this widget in your Java code? Should you omit the generic type there too and incur the wrath of the compiler's warning?
Thankfully, no. UiBinder is pretty loose when it comes to types and since generic types are just hints, you can get away with the following in the Java code backing the above UiBinder template:
#UiField(provided = true)
myWidget<Date> myWidget = new myWidget(new Date(), new Date());
Alternatively, you can also use an #UiFactory method, as mentioned in the documentation.
I am new to GWT and trying to making a page which is trying to inherit a composite widget but the value of the composite widget is dynamic.
My main page is somehting like:
.....
.....
<g:Button>Open composite widget</g:button>
.....
.....
which is opening an another popup panel which is something like:
.....
<table>
<tr><td>Top: <myCompany:userMeasurementUnit/> </td></tr>
<tr><td>Bottom: <myCompany:userMeasurementUnit/> </td></tr>
<tr><td>Left: <myCompany:userMeasurementUnit/> </td></tr>
<tr><td>Right: <myCompany:userMeasurementUnit/> </td></tr>
</table>
the above should show us
top (cm)
bottom (cm)
left (cm)
right (cm)
But I don't know how to pass the values from main page to custom widget i.e usermeasurementunit
<myCompany:userMeasurementUnit/>
My usermeasurementunit is something like:
UIBinder:
<htmlpanel tag="span" ui:field="unit"/>
and the composit widget is
usermeasurementunit extends Composite {
public usermeasurementunit(){
initwidget...
}
public onload() {
...
}
}
Now I want to pass any measurement unit cm or inches or meters upon clicking button. I tried it using the event bus but it didnt help because when I click the button popuppanel is not on the screen and its not catching the event. If any one of you can help me regarding this I would be really thankful as I am really struggling with this thing.
kind regards
First of all, you need to understand the object instantiation flow in GWT.
They call it "delayed binding", not "dynamic binding".
Uibinder xml file is a layout template. And the JAva source bean behind it is known in general programming terms as the "code-behind".
The role or purpose of the uibinder layout template is to off-load the laying-out (on the internet many non-English speaking programmers write "lay-outing" which, though syntax-wise amusing, is the same thing) so that the code-behind could be focused on controlling the layout's responses.
It's akin to the MVP attitude. View implementation separated from presentation control. You can write the code-behind error free without even knowing exactly the positions where those fields are laid out. You could even simply supply a template where the ui elements are not properly laid out so as to concentrate on your code-behind first. Perhaps after that. one uibinder template for mobile while another for desktop - but they can share the same code-behind.
The values displayed effected by the uibinder template is determined once-and-for-all during uibind. There is no dynamic binding of a uibinder field to the ever changing value of an object/variable declared in the code-behind.
To dynamically change/propagate the values of a uibinder field after uibind, you have to deliberately set its value in the code-behind or write a listener to detect its change.
public class Graceland {
#UiField
Label pressure;
#UiField
Button reset;
public void setPressure(int value) {
pressure.setText(value);
}
#UiHandler("reset")
void nameDoesNotMatter(ClickEvent ev) {
pressure.setText(default);
}
}
GWT.create() generates the Java source for the template during compile time. GWT.create is not a run-time function.
#UiField and #UiHandler are bound to the uifield in the template during uibind.
The role of uibind() is mostly not run-time but compile time too. Though, its finality is realised during run-time, all the javascript code and respective values to construct the objects are generated during compile time and executed once and only once during uibind at run-time.
Therefore, the intention is not to be able to completely replace the dynamic role of the code-behind but simply to free it from the task of laying-out, so that we the programmer could have a clean piece of code-behind being smudged as little as possible with the spaghetti source of the layout.
However, if you wish to "dynamically" affect the value of a uibinder field during bind time,then Ui:with is your friend.
package z.mambazo;
public class Graceland {
....
String initialPressure(){
/* "dynamically" obtain the pressure from the
* pressure gauge in the petroleum distillation stack
* during uibind
*/
}
}
Graceland.ui.xml:
<ui:UiBinder blah...blah>
<ui:with type="z.mambazo" field="zulu"/>
<g:VerticalPanel>
<g:Label
ui:field="pressure"
text="the temperature is :{zulu.initialPressure}"/>
</g:VerticalPanel>
</ui:UiBinder>
The ui:with bean does not have to be the template's code-behind. Either the ui:with bean has an no-argument constructor or you have to supply ui:with tag with attributes corresponding to the constructor arguments.
You have to take note that in order to use ui:with, the init value must be declared in the value attribute not in the tag text.
<g:Label
ui:field="pressure"
text="the temperature is : {zulu.initialPressure}"/>
Not
<g:Label ui:field="pressure">
the temperature is : {zulu.initialPressure}
</g:Label>
The second way, would simply reproduce the text as is.
However, you could also do it this way:
<g:HtmlPanel>
the temperature is :
<g:Label ui:field="pressure"
text="{zulu.initialPressure}"/>
</g:HtmlPanel>
Also, be reminded that all GWT UI Java code, even the interim generated ones, are all translated into browser Javascript. So, whatever class you reference with ui:with must be in Java source code not Java byte code. And those source code must not at any time down the calling chain call byte code.
What you need are shared resources. Here is an example:
MeasurementConstants.java:
package com.acme.client;
public class MeasurementConstants {
private final String measurementUnit;
public MeasurementConstants(String measurementUnit) {
this.measurementUnit = measurementUnit;
}
public String measurementUnit() {
return measurementUnit;
}
}
UiBinderMeasurement.java:
package com.acme.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
public class UiBinderMeasurement extends Composite {
private static UiBinderI18nUiBinder uiBinder = GWT
.create(UiBinderI18nUiBinder.class);
private MeasurementConstants constants;
interface UiBinderI18nUiBinder extends UiBinder<Widget, UiBinderMeasurement> {
}
public UiBinderMeasurement(MeasurementConstants constants) {
this.constants = constants;
initWidget(uiBinder.createAndBindUi(this));
}
#UiFactory
public MeasurementConstants getConstants() {
return constants;
}
}
UiBinderMeasurement.ui.xml:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:with type="com.acme.client.MeasurementConstants" field="constants"></ui:with>
<g:HTMLPanel>
<table>
<tr><td><g:Label text="Top ({constants.measurementUnit}):" /> </td></tr>
<tr><td><g:Label text="Bottom ({constants.measurementUnit}):" /> </td></tr>
<tr><td><g:Label text="Left ({constants.measurementUnit}):" /> </td></tr>
<tr><td><g:Label text="Right ({constants.measurementUnit}):" /> </td></tr>
</table>
</g:HTMLPanel>
</ui:UiBinder>
Now you can call it like this:
new UiBinderMeasurement(new MeasurementConstants("cm"))