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);
Related
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;
how can I add a custom attribute to an html list element?
I tried the following but got markup exception:
WebMarkupContainer con = new WebMarkupContainer("Temp");
con.add(new AttributeAppender("note",true, new Model<String>("Alpha")));
add(con);
HTML:
<li class="segment" wicket:id="Temp">Data Usage</li>
Any suggestions for custom attributes?
Thanks.
You have to use valid markup (note the closing li tag):
<li class="segment" wicket:id="Temp">Data Usage</li>
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.
Can I execute that line of code
nav = request().path().toString()
inside of scala template like index.scala.html
I would like to have that code to check on witch side is user and to mark it on menu
using code like this in main.scala.html:
<li class="#("active".when(nav == "contact"))">
Contacts
</li>
I would recommend you different approach, create tag - resuable template, which takes Integer as an argument,
it will render menu and mark as an active different menuitem depends on value.
#(menuItem: Int)
<ul >
<li #if(menuItem==1){ class="active" } >
////
</li>
<li #if(menuItem==2){ class="active" }>
</li>
<li #if(menuItem==3){ class="active" }>
///
</li>
</ul>
from your contact page and any other page, call this tag with corresponding value, #views.html.tags.menu(1)
You can define variables like that if that is your question. If it is not your question than please try to explain your problem in more detail.
#nav = { #request().path().toString() }
I have 4 divs with content like below:
<div class="prodNav-Info-Panel">content</div>
<div class="prodNav-Usage-Panel">content</div>
<div class="prodNav-Guarantee-Panel">content</div>
<div class="prodNav-FAQ-Panel">content</div>
And a navigation list like this:
<div id="nav">
<ul id="navigation">
<li><a class="prodNav-Info" ></a></li>
<li><a class="prodNav-Usage" ></a></li>
<li><a class="prodNav-Guarantee"></a></li>
<li><a class="prodNav-FAQ" ></a></li>
</ul>
</div>
When the page is first displayed I show all the content by executing this:
$('div.prodNav-Usage-Panel').fadeIn('slow');
$('div.prodNav-Guarantee-Panel').fadeIn('slow');
$('div.prodNav-FAQ-Panel').fadeIn('slow');
$('div.prodNav-Info-Panel').fadeIn('slow');
Now, when you click the navigation list item it reveals the clicked content and hides the others, like this:
$('.prodNav-Info').click( function() {
$('div.prodNav-Info-Panel').fadeIn('slow');
$('div.prodNav-Usage-Panel').fadeOut('slow');
$('div.prodNav-Guarantee-Panel').fadeOut('slow');
$('div.prodNav-FAQ-Panel').fadeOut('slow');
});
So what I have is 4 separate functions because I do not know which content is currently displayed. I know this is inefficient and can be done with a couple of lines of code. It seems like there is a way of saying: when this is clicked, hide the rest.
Can I do this with something like $(this) and $(not this)?
Thanks,
Erik
In your particular case you maybe able to use the .sibilings() method something like this:
$(this).fadeIn().sibilings().fadeOut()
Otherwise, lets say that you have a set of elements stored somewhere that points to all of your elements:
// contains 5 elements:
var $hiders = $(".prodNavPanel");
// somewhere later:
$hiders.not("#someElement").fadeOut();
$("#someElement").fadeIn();
Also, I would suggest changing the classes for your <div> and <a> to something more like:
<div class="prodNavPanel" id="panel-Info">content</div>
....
<a class="prodNavLink" href="#panel-Info">info</a>
This gives you a few advantages over your HTML. First: the links will have useful hrefs. Second: You can easily select all your <div>/<a> tags. Then you can do this with jQuery:
$(function() {
var $panels = $(".prodNavPanel");
$(".prodNavLink").click(function() {
var m = this.href.match(/(#panel.*)$/);
if (m) {
var panelId = m[1];
$panels.not(panelId).fadeOut();
$(panelId).fadeIn();
return false; // prevents browser from "moving" the page
}
});
});