Include HTML component in Uibinder - gwt

I would like to include some HTML codes in my gwt UiBinder. For example, put a navigation menu bar in a UiBinder as follows.
MenuBarBinder.ui.xml
<g:HTMLPanel>
<div class="topnav">
<a ui:field="home" class="active" href="#home">Home</a>
<a ui:field="news" href="#news">News</a>
<a ui:field="contact" href="#contact">Contact</a>
<a ui:field="about" href="#about">About</a>
</div>
</g:HTMLPanel>
MenuBarBinder.java
public class MenuBarBinder extends Composite{
private static MenuBarBinderUiBinder uiBinder = GWT.create(MenuBarBinderUiBinder.class);
interface MenuBarBinderUiBinder extends UiBinder<Widget, MenuBarBinder> {
}
public MenuBarBinder() {
initWidget(uiBinder.createAndBindUi(this));
}
#UiField
//How can I refer the ui:field here?
}
How can I refer the ui:field in MenuBarUiBinder.java with #UiField?
Since HTML has more options on designing the UI than GWT widget, it would be very helpful to recommend a tutorial describing this.
Thanks

If the element is an anchor <a> then you would link that to a GWT AnchorElement:
<a ui:field="home" class="active" href="#home">Home</a>
...
#UiField AnchorElement home;

Related

Why a seperate markup identifier for a container and for the fragment?

Can I add multiple fragments to a container? Apparently not, but why do I need an seperate markup identifier for the container, and one for the fragment?
In HTML,
<div wicket:id="container"></div>
<div wicket:id="container2"></div>
<wicket:fragment wicket:id="myfragment">
<h3 wicket:id="dexter"></h3>
<h3 wicket:id="deedee"></h3>
</wicket:fragment>
<wicket:fragment wicket:id="myotherfragment">
<h3 wicket:id="foo"></h3>
<h3 wicket:id="bar"></h3>
</wicket:fragment>
The web page,
public class MyPage extends WebPage {
private Component container;
public MyPage() {
container=new MyFragment("container",this);
add(container);
container=new MyOtherFragment("container2",this);
add(container);
One of the fragents is (the other is alike),
public MyFragment(String id,WebPage page) {
super(id,"myfragment",page);
Label label=new Label("dexter", "Omelette du fromage");
add(label);
Label label2=new Label("deedee","That's all you can say!");
add(label2);
}
Fragments are meant for easy reuse of small components, to fill a dynamic form or similar.
When using fragment you should use a ListView to populate them. That way you can easily build dynamic markup. You need to reference the fragment you want to use and tell wicket where to place it in the markup.
Instead of the two container divs, use a list
<div wicket:id="fragmentList">
<div wicket:id="fragment"></div>
</div>
There is no point in having two fragments with the same markup in then (two H3 tags). Instead you can have a header fragment and a label fragment or whatever you need.
<wicket:fragment wicket:id="headerFragment">
<h3 wicket:id="dexter"></h3>
<h3 wicket:id="deedee"></h3>
</wicket:fragment>
<wicket:fragment wicket:id="labelFragment">
<label wicket:id="foo"></label>
<label wicket:id="bar"></label>
</wicket:fragment>
<wicket:fragment wicket:id="inputFragment">
<label wicket:id="foo"></label>
<input wicket:id="bar" type="text">
</wicket:fragment>
In your WebPage you can add the fragments needed to a list of fragment and add them to a ListView
public HomePage(final PageParameters parameters)
{
List<Fragment> fragments = Arrays.asList(new HeaderFragment("fragment", this),
new LabelFragment("fragment", this),
new InputFragment("fragment", this));
add(new ListView<Fragment>("fragmentList", fragments) {
#Override
protected void populateItem(ListItem<Fragment> item)
{
final Fragment frag = _item.getModelObject();
_item.add((Fragment) frag);
}
});
}
There's no such thing as a container here. There's the fragment, which has its own id and stands separate from the main markup tree, and there is a place where you can attach your fragment to. This place will have its own id like any other Wicket component.
So the first id in the Fragment constructor tells Wicket where to attach the fragment and the second tells it which fragment to attach there.

Dynamic nested unordered lists in GWT UIBinder

I'm trying to implement a simple CSS-based menu in GWT UIBinder, but I'm having some difficulties with one particular part.
The menu has two main-level items: "New session" and "Current sessions." When the user clicks "New session", a new list item should be added to the sublist under "Current sessions."
Here is the plain HTML version of the menu:
<div id="cssmenu">
<ul>
<li>New Session</li>
<li class="has-sub">Current Sessions
<ul>
<li>Session 1</li>
<li>Session 2</li>
</ul>
</li>
</ul>
</div>
The basic format was pretty simple to implement in UIBinder, but the dynamic sublist is giving me difficulties.
Here's the basic UIBinder template that I came up with:
The XML:
<!-- Menu.ui.xml -->
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<g:HTMLPanel id="cssmenu" ui:field="menuDiv">
<ul>
<li ui:field="newSessionItem">New Session</li>
<li class="has-sub" ui:field="currentSessionItem">
Current Sessions
<ul id="currentSessionSublist" ui:field="currentSessionSublistItem">
<li>Session 1</li>
<li>Session 2</li>
</ul>
</li>
</ul>
</g:HTMLPanel>
</ui:UiBinder>
The Java:
// Menu.java
public class Menu extends UIObject {
interface MenuBinder extends UiBinder<DivElement, Menu> {}
private static MenuBinder uiBinder = GWT.create(MenuBinder.class);
#UiField HTMLPanel menuDiv;
#UiField LIElement newSessionItem;
#UiField LIElement currentSessionItem;
#UiField UListElement currentSessionSublistItem;
public Menu() {
setElement(uiBinder.createAndBindUi(this));
}
#UiHandler("newSessionItem")
void handleClick(ClickEvent e) {
addCurrentSession();
}
private void addCurrentSession() {
// dynamic LI should be added here
}
}
I'm unsure how to add the dynamic list items in addCurrentSession(). I tried adding a custom widget that compiles to a <li> element, but was unable to add it using RootPanel.get("currentSessionSublist").add(item). I read somewhere that while it's possible to nest both HTML and Widgets inside an HTMLPanel, Widgets cannot be nested within HTML. If this is the case, how would I go about adding items to the sublist? I was hoping to go the widget route so I could later add the ability to remove a specific list item programmatically.
I don't want to use GWT's Menu, MenuItem, etc because those compile to tables.
Try this to dynamically add an item to a list (ordered/unordered):
final LIElement listItem = Document.get().createLIElement();
listItem.setInnerText("your text"); // or setInnerHTML("...")
this.currentSessionSublistItem.appendChild(listItem);
The crux is to go through the HTMLPanel:
menuDiv.add(item, currentSessionSublistItem);

Gwt UIBinder DockLauout north element raise error as must contain a widget, but found <app:HeaderPanel ui:field='headerPanel'>

While trying to use Gwt UIBinder to have a custom widget loaded from main UI i am getting exception as
[ERROR] <g:north size='5'> must contain a widget, but found <app:HeaderPanel ui:field='headerPanel'> Element <g:DockLayoutPanel styleName='{style.outer}' unit='EM'> (:8)
while parsing XML in development mode. Below is the XML which I created for the same
<!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:app='urn.import:com.test.test.client'
xmlns:test='urn.import=com.test.test.client'>
<ui:style src="Resources/GlobalStyles.css" />
<g:DockLayoutPanel unit='EM' styleName='{style.outer}'>
<g:north size='5'>
<app:HeaderPanel ui:field='headerPanel' />
</g:north>
<g:west size='14'>
<test:FriendList ui:field='friendList' />
</g:west>
<g:center>
<g:HTMLPanel styleName='{style.boxPadding}'>
<div class="{style.titleBar}">Latest Activity</div>
<g:ScrollPanel ui:field='mainPanel' styleName='{style.mainPanel}' />
</g:HTMLPanel>
</g:center>
<g:south size="3">
<g:HTMLPanel styleName='{style.footerPanel}'>
<div>
Contact us
|
Privacy
|
About
</div>
</g:HTMLPanel>
</g:south>
</g:DockLayoutPanel>
</ui:UiBinder>
The headerPanel widget exits in the hierarchy. The corresponding code for above UiBinder is given below
public class TestApp implements EntryPoint {
#UiField
HeaderPanel headerPanel;
#UiField
ScrollPanel mainPanel;
RootLayoutPanel root;
private static TestApp singleton;
public static TestApp get() {
return singleton;
}
interface TestAppUiBinder extends UiBinder<DockLayoutPanel, TestApp> {
}
private static TestAppUiBinder uiBinder = GWT
.create(TestAppUiBinder.class);
#Override
public void onModuleLoad() {
// TODO Auto-generated method stub
singleton = this;
DockLayoutPanel outer = uiBinder.createAndBindUi(this);
root = RootLayoutPanel.get();
root.add(outer);
}
}
Basically I am novice in Gwt and trying to learn the things. Any pointer in this regard will be a great help.
Thanks.
What is
<app:HeaderPanel ui:field='headerPanel' />? If it does not extend Widget then it will not work. Try putting <g:Label>FOO</g:Label> in there and see if it works. Also make sure that your xmlns is correct. It will look for Header Panel in the package com.test.test.client. If you are trying to use the gwt Header Panel then it needs to be
<g:HeaderPanel ui:field="headerPanel" />
I think you are misunderstanding the xmlns. This tells gwt where to look for your java class. Both app and test are pointing to the same package. You should only add namespaces when you want to include your own custom widget classes or extra things like CellTable and DataGrid. I believe you are wanting to use the header.
Issue got fixed as it was xml parsing issue.
Thanks for providing inputs.

ui:with, style not showing up

I would like to share a CSS across multiple widgets using .
I can see that css class name are obfuscated but the class definition
is not showing up when I inspect the element in firefox / chrome.
Here're my codes. Can anyone suggest what am I missing? Thanks.
Style.css
.nameSpan { color: #3E6D8E; background-color: #E0EAF1;}
Resources.java
public interface Resources extends ClientBundle {
#Source("Style.css")
Style style();
public interface Style extends CssResource {
String nameSpan();
}
}
uibinder.ui.xml
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:with field='res' type='com.my.app.widgets.logoname.Resources'/>
<g:HTMLPanel>
<div>
Well hello there
<g:InlineLabel ui:field='nameSpan' styleName="res.style.nameSpan">kevin</g:InlineLabel>
</div>
</g:HTMLPanel>
</ui:UiBinder>
uibinder.class
public class uibinder extends Composite {
private static uibinderUiBinder uiBinder = GWT.create(uibinderUiBinder.class);
interface uibinderUiBinder extends UiBinder<Widget, uibinder> {}
#UiField(provided = true) final Resources res; // the style doesn't show no matter provided=true is declared or not.
public uibinder(Resources res) {
res = GWT.create(Resources.class);
initWidget(uiBinder.createAndBindUi(this));
}
You have to use res.style().ensureInjected()
You need to assign the style (styleName attribute) somewhere. For example:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:with field='res' type='com.my.app.widgets.logoname.Resources'/>
<g:HTMLPanel>
<div>
Well hello there
<g:InlineLabel ui:field='nameSpan' styleName="{res.nameSpan}">kevin</g:InlineLabel>
</div>
</g:HTMLPanel>
</ui:UiBinder>
The attribute ui:field you've declared does not set the css style. It defines the attribute that is to be filled in in your uibinder class. See the GWT doc for some guidance.

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