TurboManage

David Chandler's Journal of Java Web and Mobile Development

  • David M. Chandler

    Google Cloud Platform Data Engineering Instructor with ROI Training now residing in Colorado with the wife of my youth (31 years). Besides tech, I enjoy aviation and landscape photography.

  • Subscribe

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,120 other subscribers
  • Sleepless Nights…

    February 2010
    S M T W T F S
     123456
    78910111213
    14151617181920
    21222324252627
    28  
  • Blog Stats

    • 1,046,345 hits

Simplifying GWT Markup with HTML Widgets

Posted by David Chandler on February 11, 2010

The more I’ve worked with CSS and GWT, the more I’ve tried to simplify the markup that GWT creates. GWT spits out a lot of extraneous DIVs, which, while providing maximum flexibility, result in bloated markup. For example, here’s some GWT code to create a simple horizontal menu of hyperlinks:

	public void setMenu(List<MenuItem> items)
	{
		// userMenu is a HorizontalPanel
		userMenu.clear();
		for (int i=0; i<items.size(); i++)
		{
			MenuItem item = items.get(i);
			if (i>0)
			{
				userMenu.add(new Label ("|"));
			}
			Hyperlink y = new Hyperlink(item.getLabel(), item.getUrl());
			userMenu.add(y);
		}
	}

And here’s the resulting markup, courtesy of Firebug (an indispensable tool for CSS work, especially in GWT):

<table cellspacing="0" cellpadding="0" id="detail_menu">
	<tbody>
		<tr>
			<td align="left" style="vertical-align: bottom;">
				<div class="gwt-Hyperlink">
					<a href="#prayers">Prayers</a>
				</div>
			</td>
			<td align="left" style="vertical-align: bottom;">
				<div class="gwt-Label">|</div>
			</td>
			<td align="left" style="vertical-align: bottom;">
				<div class="gwt-Hyperlink">
					<a href="#manage_lists">Manage Lists</a>
				</div>
			</td>
		</tr>
	</tbody>
</table>

That’s quite a bit of markup for a simple menu of hyperlinks, albeit it requires very little CSS. The HorizontalPanel ensures the hyperlinks appear horizontally, so really all the CSS that’s needed is a little padding in each TD to space things out.

A simpler alternative for menus used by many Web designers is the humble unordered list. Unfortunately, GWT does not have widgets that spit out the lowly UL and LI tags. You can always do it manually using the HTML or InlineHTML widgets; however, it is more satisfying to use real widgets, so I created an UnorderedListWidget and ListItemWidget. Here is the previous GWT menu code rewritten using the new widgets:

	public void setMenu(List<MenuItem> items)
	{
		// userMenu is an UnorderedListWidget
		userMenu.clear();
		for (int i=0; i<items.size(); i++)
		{
			MenuItem item = items.get(i);
			if (i>0)
			{
				userMenu.add(new ListItemWidget("|"));
			}
			Hyperlink y = new Hyperlink(item.getLabel(), item.getUrl());
			userMenu.add(new ListItemWidget(y));
		}
	}

And here’s the much leaner markup (unfortunately, I do not know a way to get rid of the unnecessary Hyperlink DIVs apart from creating a lightweight Hyperlink widget):

<ul id="detail_menu" class="roa-hMenu">
	<li>
		<div class="gwt-Hyperlink">
			<a href="#prayers">Prayers</a>
		</div>
	</li>
	<li>|</li>
	<li>
		<div class="gwt-Hyperlink">
			<a href="#manage_lists">Manage Lists</a>
		</div>
	</li>
</ul>

Finally, here are the widgets. It’s easy to generate any HTML markup you need this way, thanks to GWT’s Document and Element hierarchies.

package com.turbomanage.gwt.client.ui.widget;

import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.UListElement;
import com.google.gwt.user.client.ui.ComplexPanel;
import com.google.gwt.user.client.ui.Widget;

public class UnorderedListWidget extends ComplexPanel
{
	public UnorderedListWidget()
	{
		setElement(Document.get().createULElement());
	}

	public void setId(String id)
	{
		// Set an attribute common to all tags
		getElement().setId(id);
	}

	public void setDir(String dir)
	{
		// Set an attribute specific to this tag
		((UListElement) getElement().cast()).setDir(dir);
	}

	public void add(Widget w)
	{
		// ComplexPanel requires the two-arg add() method
		super.add(w, getElement());
	}
}
package com.turbomanage.gwt.client.ui.widget;

import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;

public class ListItemWidget extends SimplePanel
{
	public ListItemWidget()
	{
		super((Element) Document.get().createLIElement().cast());
	}

	public ListItemWidget(String s)
	{
		this();
		getElement().setInnerText(s);
	}

	public ListItemWidget(Widget w)
	{
		this();
		this.add(w);
	}
}

Enjoy!

10 Responses to “Simplifying GWT Markup with HTML Widgets”

  1. perwiklander said

    Yep this is what I do myself as well. Although I have to say I’m a lot more tolerant of the bloated HTML when using GWT than if I write it myself.

    1. It is generated in the browser and not sent over the wire
    2. No one has to manage it with a text editor.

    It won’t get rid of the div but you can use InlineHyperlink.

    You can also get rid of that pipe you insert between items. Just add a border-right with CSS instead (and border-right: 0px, on the last element).

  2. Erron said

    I like the widgets for navigation. To reduce the bloat, we don’t use any of the layouts. Instead we just use FlowPanel and CSS to create our desired layout. I understand that GWT 2.0 has div only layouts, but I have not looked at the generated html.

    I would also agree with Perwiklander post with one caveat: It makes styling with custom css much harder with all the extra bloat.

    • Erron said

      Re: I like the widgets for navigation

      I was talking about your custom widgets.

    • Thanks, Erron. I’m also using FlowPanels only for layout now, and have thought of eliminating even those in favor of native DivElements in order to reduce the event processing overhead associated with Widgets as described in one of last year’s Google I/O presentations. If I understand correctly, the Widgets in this post still have some event processing overhead because they extend Widget, although perhaps the compiler would be smart enough to omit unused methods?

  3. Nathan Wallman said

    Thanks for sharing this. I was just looking for the best way to do this and came across this post. Saved me a bit of time!

  4. kimi said

    Thanx for sharing this. just found out your blog via gwt-googlegroups.
    is there any bestpractice using uibinder with customwidget to reduce bloated tested tags & ease custom layout with css ?

  5. Thanks, kimi. I’m not aware of any best practices per se, but the direction of the new cell widgets in GWT 2.1 is to use raw HTML wherever possible because Widgets incur event processing and other overhead, especially in large tables where you might have multiple Widgets per row. Check out the cell widgets dev guide and the GWT sessions from last year’s Google I/O.

  6. Terry said

    How would I add a clicklistener to the li tags

    • dersani said

      Hope it’s not to late to answer your post.

      Use InlineLabels, add them as widgets and add a ClickHandler to them.

      Untested, but it should work.

  7. Rene said

    Hello, I like this article, I was wondering how to hide/show or expand/collapse the elements () of when it is clicked, In your example, what should I do in order to hide/show elements of “detail_menu”.

Leave a comment