GWT Popup and UIBinder: Panel or DialogBox? - gwt

I have a requirement where, when a button is clicked, the user should be prompted with a popup/dialog box to enter some additional details such as last name, DOB, etc.I tried to play with window.confirm() but I think this does not serve my purpose. Can some help me how this can be achieved in GWT through UIBinder?
I tried some thing like this in my UI binder.xml
<g:HTMLPanel visible="false" >
<g:DialogBox ui:field="dialogPanel"
animationEnabled="true" modal="false" glassEnabled="false">
<g:caption>More Details</g:caption>
<table>
<tr>
<td colspan="2" align="center">
<g:Datepicker ui:field="DOB">DOB:</g:Datepicker>
</td>
</tr>
<tr>
<td>UserName:</td>
<td>
<g:TextBox ui:field="usernameTextBox" />
</td>
</tr>
<tr>
<td></td>
<td align="right">
<g:Button ui:field="loginButton">OK</g:Button>
</td>
</tr>
</table>
</g:DialogBox>
</g:HTMLPanel>
I am not sure which one to go with: popup or dialog box!
Thanks.

Here is the skeleton for a GWT Dialog box using uibinder:
MyDialogBox.java
import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.Widget;
public class MyDialogBox extends DialogBox {
private static final Binder binder = GWT.create(Binder.class);
interface Binder extends UiBinder<Widget, MyDialogBox> {
}
public MyDialogBox() {
setWidget(binder.createAndBindUi(this));
setAutoHideEnabled(true);
setText("My Title");
setGlassEnabled(true);
center();
}
}
MyDialog.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:style>
.panel {
background-color: ivory;
}
</ui:style>
<g:FlowPanel styleName="{style.panel}">
<g:Label>Dialog Content</g:Label>
</g:FlowPanel>
</ui:UiBinder>
show it using:
MyDialogBox m = new MyDialogBox();
m.show();

DialogBox is a child of PopupPanel and has all its features. Additionally it has (from the docs):
..caption area at the top and can be dragged by the user.
About usage in UiBinder (again from the docs):
DialogBox elements in UiBinder templates can have one widget child and one
<g:caption> child.
So it seems that you need to replace your <table> with a GWT widget, most probably <g:HTMLPanel> and put whole <table> inside it.
Also, PopupPanel and DialogBox are standalone widgets and normally do not get added to other Widgets, but are shown via .show() and hide() methods. So, in your UiBinder, you can put
<g:DialogBox> at the root level.

Related

GWT: switching from <table> to g:LayoutPanel and g:layer disable all input

I'm using uiBinder to layout my views in a gwt project and I've been using a regular table to handle the basic layout of the view. It became kinda messy and static so I was looking into using layers inside a layoutPanel instead. This seemed like a better way of doing it. So before I had the structure:
docklayoutpanel
center
tablayoutpanel
tab
table
// tabel rows and cells with various content
and now the table with its rows and columns has been replaced with a layoutPanel with layers. At first it seemed to work fine, looking almost exactly the same (just some margins and padding were off), but then I noticed that all the content inside the layers were completely disabled. Not only buttons and textFields, but I can't even select static text. It's like there's an invisible glass pane over everything. What is causing this and how do I fix it?
Throwing in some code as well. This is what the beginning looked like before (working fine):
<g:DockLayoutPanel unit="EM" height="100%">
<g:center>
<g:TabLayoutPanel barUnit='EM' barHeight='3'
ui:field="tabs">
<!-- TABB 1 -->
<g:tab>
<g:header styleName="viewSubtitleText">
<!-- Flikrubrik -->
View Person
</g:header>
<g:LayoutPanel>
<g:layer>
<g:ScrollPanel>
<g:HTMLPanel>
<table>
<tr>
<td valign="top">
<g:HTMLPanel styleName="roundedBox">
<g:HTMLPanel styleName="viewSubtitleText">People</g:HTMLPanel>
<table>
<tr>
<td>
<table>
<tr>
<td>
<g:HTML>Search </g:HTML>
</td>
<td>
<j:DemiaSuggestBox ui:field="sgtPerson"></j:DemiaSuggestBox>
</td>
And it was replaced by this:
<g:DockLayoutPanel unit="EM" height="100%">
<g:center>
<g:TabLayoutPanel barUnit='EM' barHeight='3'
ui:field="tabs">
<!-- TABB 1 -->
<g:tab>
<g:header styleName="viewSubtitleText">
<!-- Flikrubrik -->
View Person
</g:header>
<g:LayoutPanel>
<g:layer styleName="roundedBox">
<g:HTMLPanel>
<g:HTMLPanel styleName="viewSubtitleText">People</g:HTMLPanel>
<table>
<tr>
<td>
<table>
<tr>
<td>
<g:HTML>Search </g:HTML>
</td>
<td>
<j:DemiaSuggestBox ui:field="sgtPerson"></j:DemiaSuggestBox>
</td>
So it turned out I just forgot to specify the dimension of the layers, e.g:
<g:layer left="1em" top="1em" bottom="1em" width="42em">

How do you do nested Editors in GWT2?

Сould you please give me working example of nested editors ? I've read this document but it didn't help me. In my code I have class Person and Organization.
Organization has field contactPerson of a type Person.
So I created following editor for Person:
public class PersonEditor extends Composite implements Editor<PersonProxy>
{
interface PersonEditorUiBinder extends UiBinder<Widget, PersonEditor>
{
}
private static PersonEditorUiBinder uiBinder = GWT.create(PersonEditorUiBinder.class);
#UiField
ValueBoxEditorDecorator<String> name;
#UiField
ValueBoxEditorDecorator<String> phoneNumber;
#UiField
ValueBoxEditorDecorator<String> email;
#UiField
CaptionPanel captionPanel;
public void setCaptionText(String captionText)
{
captionPanel.setCaptionText(captionText);
}
public PersonEditor()
{
initWidget(uiBinder.createAndBindUi(this));
}
}
its corresponding .ui.xml is
<!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'
xmlns:e='urn:import:com.google.gwt.editor.ui.client'
ui:generateFormat='com.google.gwt.i18n.rebind.format.PropertiesFormat'
ui:generateKeys="com.google.gwt.i18n.server.keygen.MD5KeyGenerator"
ui:generateLocales="en,ru">
<ui:style src="../common.css"/>
<g:CaptionPanel captionText="Test" ui:field="captionPanel">
<g:HTMLPanel>
<table class="{style.forform}">
<tr>
<th class="{style.forform}">
<div>
<ui:msg meaning="person's name">Name:</ui:msg>
</div>
</th>
<td class="{style.forform}">
<e:ValueBoxEditorDecorator ui:field="name" stylePrimaryName="{style.forform}">
<e:valuebox>
<g:TextBox stylePrimaryName="{style.forform}"/>
</e:valuebox>
</e:ValueBoxEditorDecorator>
</td>
</tr>
<tr>
<th class="{style.forform}">
<div>
<ui:msg>Phone Number:</ui:msg>
</div>
</th>
<td class="{style.forform}">
<e:ValueBoxEditorDecorator ui:field="phoneNumber" stylePrimaryName="{style.forform}">
<e:valuebox>
<g:TextBox width="100%" stylePrimaryName="{style.forform}"/>
</e:valuebox>
</e:ValueBoxEditorDecorator>
</td>
</tr>
<tr>
<th class="{style.forform}">
<div>
<ui:msg>EMail:</ui:msg>
</div>
</th>
<td class="{style.forform}">
<e:ValueBoxEditorDecorator ui:field="email" stylePrimaryName="{style.forform}">
<e:valuebox>
<g:TextBox width="100%" stylePrimaryName="{style.forform}"/>
</e:valuebox>
</e:ValueBoxEditorDecorator>
</td>
</tr>
</table>
</g:HTMLPanel>
</g:CaptionPanel>
</ui:UiBinder>
It works nicely.
Here is editor for Organization:
public class OrganizationEditor extends Composite implements Editor<OrganizationProxy>
{
interface OrganizationEditorUiBinder extends UiBinder<Widget, OrganizationEditor>
{
}
private static OrganizationEditorUiBinder uiBinder = GWT.create(OrganizationEditorUiBinder.class);
#UiField
CaptionPanel captionPanel;
#UiField
ValueBoxEditorDecorator<String> name;
#UiField
ValueBoxEditorDecorator<String> address;
#UiField
PersonEditor personEditor;
public void setCaptionText(String captionText)
{
captionPanel.setCaptionText(captionText);
}
public OrganizationEditor()
{
initWidget(uiBinder.createAndBindUi(this));
}
}
and its corresponding .ui.xml is
<!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'
xmlns:e='urn:import:com.google.gwt.editor.ui.client'
xmlns:c='urn:import:com.zasutki.courierApp.client.customer'
xmlns:myui='urn:import:com.zasutki.courierApp.client.ui'
ui:generateFormat='com.google.gwt.i18n.rebind.format.PropertiesFormat'
ui:generateKeys="com.google.gwt.i18n.server.keygen.MD5KeyGenerator"
ui:generateLocales="en,ru">
<ui:style src="../common.css"/>
<g:CaptionPanel ui:field="captionPanel">
<myui:VerticalFlowPanel>
<g:HTMLPanel>
<table class="{style.forform}">
<tr>
<th class="{style.forform}">
<div>
<ui:msg meaning="Name of organization">Name:</ui:msg>
</div>
</th>
<td class="{style.forform}">
<e:ValueBoxEditorDecorator ui:field="name" stylePrimaryName="{style.forform}">
<e:valuebox>
<g:TextBox stylePrimaryName="{style.forform}"/>
</e:valuebox>
</e:ValueBoxEditorDecorator>
</td>
</tr>
<tr>
<th class="{style.forform}">
<div>
<ui:msg>Address:</ui:msg>
</div>
</th>
<td class="{style.forform}">
<e:ValueBoxEditorDecorator ui:field="address" stylePrimaryName="{style.forform}">
<e:valuebox>
<g:TextBox stylePrimaryName="{style.forform}"/>
</e:valuebox>
</e:ValueBoxEditorDecorator>
</td>
</tr>
</table>
<c:PersonEditor ui:field="personEditor" captionText="Contact person">
<ui:attribute name="captionText"/>
</c:PersonEditor>
</g:HTMLPanel>
</myui:VerticalFlowPanel>
</g:CaptionPanel>
</ui:UiBinder>
interface for proxy of Organization is
#ProxyFor(value = Organization.class, locator = ObjectifyLocator.class)
public interface OrganizationProxy extends EntityProxy
{
public String getName();
public void setName(String name);
public String getAddress();
public void setAddress(String address);
public PersonProxy getContactPerson();
public void setContactPerson(PersonProxy contactPerson);
}
and finally here is class that uses all described above
public class NewOrderView extends Composite
{
interface Binder extends UiBinder<Widget, NewOrderView>
{
}
private static Binder uiBinder = GWT.create(Binder.class);
// Empty interface declaration, similar to UiBinder
interface OrganizationDriver extends SimpleBeanEditorDriver<OrganizationProxy, OrganizationEditor>
{
}
OrganizationDriver driver = GWT.create(OrganizationDriver.class);
#UiField
Button save;
#UiField
OrganizationEditor orgEditor;
OrganizationProxy organizationProxy;
public NewOrderView()
{
initWidget(uiBinder.createAndBindUi(this));
organizationProxy = createFactory().contextOrder().create(OrganizationProxy.class);
// Initialize the driver with the top-level editor
driver.initialize(orgEditor);
// Copy the data in the object into the UI
driver.edit(organizationProxy);
}
#UiHandler("save")
void buttonClick(ClickEvent e)
{
e.stopPropagation();
OrganizationProxy edited = driver.flush();
PersonProxy person = edited.getContactPerson();
// person is always null !!!
if (driver.hasErrors())
{
}
}
}
The question is why nested editor (PersonEditor) doesn't get flushed automatically ? Is it supposed to happen ? What is the proper solution ?
<e:ValueBoxEditorDecorator ui:field="contactPerson">
<e:valuebox>
<c:PersonEditor captionText="Contact person">
<ui:attribute name="captionText"/>
</c:PersonEditor>
</e:valuebox>
</e:ValueBoxEditorDecorator>
This code throws the exception. After <e:valuebox> a sub-type of a ValueBox is expected (e.g. TextBox, DoubleBox,...). Your PersonEditor is not a ValueBox (and it makes no sense to make it one). So just add your PersonEditor in the OrganizationEditor's ui.xml like a normal Widget.
For example:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
....>
<ui:style src="../common.css"/>
<g:CaptionPanel ui:field="captionPanel">
<myui:VerticalFlowPanel>
<g:HTMLPanel>
<table class="{style.forform}">
// your other input fields
</table>
</g:HTMLPanel>
// Add the PersonEditor to the FlowPanel
<c:PersonEditor captionText="Contact person">
<ui:attribute name="captionText"/>
</c:PersonEditor>
</myui:VerticalFlowPanel>
</g:CaptionPanel>
</ui:UiBinder>
In the Java class, change
#UiField
ValueBoxEditorDecorator<PersonEditor> contactPerson;
to
#UiField
PersonEditor contactPerson;
Ah... I have to create proxy for contactPerson manually!
public class NewOrderView extends Composite
{
public NewOrderView()
{
initWidget(uiBinder.createAndBindUi(this));
AdminRequestFactory.OrderRequestContext orderRequestContext = createFactory().contextOrder();
organizationProxy = orderRequestContext.create(OrganizationProxy.class);
organizationProxy.setContactPerson(orderRequestContext.create(PersonProxy.class));
// Initialize the driver with the top-level editor
driver.initialize(orgEditor);
// Copy the data in the object into the UI
driver.edit(organizationProxy);
}
}

Setting alignment in verticalpanel - gwt

I am trying to set the align property in vertical panel in GWT like this:
vpanel = new VerticalPanel();
vPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
and then adding children which gives me a table like this:
<table>
<tbody>
<tr><td align="left"></td></tr>
<tr><td align="left"></td></tr>
</tbody>
</table>
But what I want is
<table align="left">
<tbody>
<tr><td></td></tr>
</tbody>
</table>
I know it's a stupid question but I am stuck with browser compatibility issue and only the HTML specified fixes issue on all browsers. Any ideas?
You can get the underlying element of a widget and set an attribute to it using getElement().setAttribute(..) for instance :
VerticalPanel panel = new VerticalPanel();
panel.getElement().setAttribute("align", "left");
RootPanel.get().add(panel);

uiBinder on Button Clickevent

I'm trying to use uiBinder. I followed the tutorial provided by
google, but I don't know why clickevent doesn't work? I want to count number of clicks and show it in the span, it doesn't work, I also put window.alert but it seems that the event handler is not called at all! Can anyone help me? It's couple of hours I'm working on it but can't find the problem!
Thank you so much
P.S.
Below is my code
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:style>
</ui:style>
<g:HTMLPanel>
<table>
<tr>
<td><img ui:field='imgPrd'/></td>
<td>
<span ui:field='lblNum'></span>
<g:Button ui:field='btnAdd'></g:Button>
</td>
</tr>
</table>
</g:HTMLPanel>
public class uiProductList extends Composite {
#UiField Button btnAdd;
#UiField ImageElement imgPrd;
#UiField SpanElement lblNum;
int count;
private static uiProductListUiBinder uiBinder =
GWT.create(uiProductListUiBinder.class);
interface uiProductListUiBinder extends UiBinder<Widget,
uiProductList> {
}
public uiProductList() {
initWidget(uiBinder.createAndBindUi(this));
}
#UiHandler("btnAdd")
void handleClick(ClickEvent e) {
Window.alert("test");
count++;
lblNum.setInnerText(Integer.toString(count));
}
}
You should correctly add your widget to the root panel. Use
RootPanel.get().add(uiProduct);
Otherwise the handlers are not initialized.
I had exactly the same problem and here is the conclusion:
RootPanel.getBodyElement().appendChild(uiProduct.getElement()); - NOT WORKING
RootPanel.get().add(uiProduct); - WORKING FINE

GWT: uiBinder-based widget cant be instanced second time

I created a widget using GWT uiBinder. It works fine, till the moment when I want to instance it second time. After i call constructor second time it returns only raw description from XML and statements in constructor (rootElement.add( new HTML( "panel1" ), leftId );) are just don't work. It throws no error or warning.
Please help
Java class:
public class DashboardLayout extends Composite {
final String leftId = "boxLeft";
final String rightId = "boxRight";
interface DashboardLayoutUiBinder extends UiBinder<HTMLPanel, DashboardLayout> {
}
private static DashboardLayoutUiBinder ourUiBinder = GWT.create( DashboardLayoutUiBinder.class );
#UiField
HTMLPanel htmlPanel;
public DashboardLayout() {
HTMLPanel rootElement = ourUiBinder.createAndBindUi( this );
this.initWidget( rootElement );
rootElement.add( new HTML( "panel1" ), leftId );
rootElement.add( new HTML( "panel2" ), rightId );
}
}
XML descriprion:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
>
<g:HTMLPanel ui:field="htmlPanel">
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="40%" id="boxLeft" class="boxContextLeft">
</td>
<td width="60%" id="boxRight" class="boxContextRight">
</td>
</tr>
</table>
</g:HTMLPanel>
</ui:UiBinder>
Don't use id="myid" in widgets, as they will be global(which will screw you up) instead of scoped per instantiation of the widget; use ui:field="myid" and then create a corresponding UiField variable in the java class. This will allow the gwt compiler to obfuscate the id's so you don't get collisions between instantiations of the same widget.
DashboardLayout.java
public class DashboardLayout extends Composite {
interface DashboardLayoutUiBinder extends
UiBinder<HTMLPanel, DashboardLayout> {
}
private static DashboardLayoutUiBinder ourUiBinder = GWT
.create(DashboardLayoutUiBinder.class);
#UiField
HTMLPanel htmlPanel;
#UiField
HTML panel1;
#UiField
HTML panel2;
public DashboardLayout() {
HTMLPanel rootElement = ourUiBinder.createAndBindUi(this);
this.initWidget(rootElement);
// do stuff with panel1
panel1.setHTML("<blink>blink</blink>");
// do stuff with panel2
panel2.setHTML("<marquee>marquee</marquee>");
}
}
DashboardLayout.ui.xml
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<g:HTMLPanel ui:field="htmlPanel">
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="40%" class="boxContextLeft">
<g:HTML ui:field="panel1"></g:HTML>
</td>
<td width="60%" class="boxContextRight">
<g:HTML ui:field="panel2"></g:HTML>
</td>
</tr>
</table>
</g:HTMLPanel>
</ui:UiBinder>