Wednesday, October 24, 2007

Wicket and HTML CSS attributes

JAVA open source web frameworks are everywhere. And the documentation is everywhere, which is not always a good thing. Especially when what you want is to go to a particular somewhere to find all of the documentation. Mailing lists are great, but you may end up the first to post on your problem. As long as you don't need to get it done---you have no problem.

I didn't find a post or documentation that addressed the problem I was facing today.

In this case, the task I had to complete was simple: render an HTML table, alternating the background color for each row. I've implemented this pattern a half dozen times before using Java Servlets, ASP, PHP, OpenLaszlo and even a Struts-like home-grown system when working for a previous employer. In the end, it has always come down to plain old HTML and CSS, programatically assigning one of two CSS classes to a table row. (OpenLaszlo was an exception.)

This time around I'm using Wicket. I must admit that I'm not to crazy about heavy, rule-wielding web frameworks because they often improve on the way you accomplish big tasks, but make it exponentially more difficult to do the simple ones that don't fit nicely into their design. Is this true of Wicket? It's too early for me to say, but I'm certainly interested in finding the answer to that question.

The early verdict: So far, Wicket seems to do a pretty decent job doing what a framework ought to do.

Wicket keeps the presentation concerns separate from the model. In practical term this means that the web stuff (javascript, CSS, HTML) is kept independent from the JAVA source. No mixing-and-matching within a single file. Wicket does a lot more, but I'll leave it to others to sell you on it.

For a non-Wicket web app, the type of logic required to provide alternating rows is normally applied in a for loop, using mod to determine if you are dealing with an even or odd row. In a scripting language, the whole operation takes all of two lines of code.

So I set out to do the same for Wicket. Fifteen minutes of googling and I found How to modify an attribute on a HTML tag. Sounded promising, but upon reading, looked verbose. (Must we really use a separate model and view to create a simple attribute pair?)

Reading this page, it wasn't apparent how the example would lend itself to my case. However, with some experimentation, I was able to retrofit the familiar pattern onto the Wicket frame.



<tr wicket:id="catalog" class="unknown">
<td wicket:id="name"></td>
<td wicket:id="sku"></td>
<td wicket:id="manufacturer"></td>
...
</tr>


ListView listview1 = new ListView("catalog", catalogItems.getProductWindow())
{
public final String style1 = "row_light";
public final String style2 = "row_dark";

protected void populateItem(ListItem item)
{
Map rec = (Map) item.getModelObject();

item.add(new Label("name", (String)rec.get("cttm_display")));
item.add(new Label("sku", (String)rec.get("cttm_partnumber")));
item.add(new Label("manufacturer", (String)rec.get("mfg_name")));
...

if (item.getIndex() % 2 == 0)
item.add(new AttributeModifier("class", new PropertyModel(this, "style1")));
else
item.add(new AttributeModifier("class", new PropertyModel(this, "style2")));

}
}



I used PropertyModel to get around having to create beans to hold the two strings representing the CSS classes. Does the reader see a better solution?

2 comments:

qwertzguy said...

Thanks for this info !

I found a way to avoid PropertyModel:
new AttributeModifier("class", new Model("style1"));

However, I can't find how to change an attribute of a [p] tag which isn't my item holder. For example:
[div wicket:id="itemholder"]
[p wicket:id="addStyle"][span wicket:id="name" /][/p]
[/div]
(replace [ and ] by < and >, Blogger doesn't accept HTML in comments)

What type should be addStyle? I tried Label, EmptyPanel but it says that it discards tag content which I don't want.
Thanks !

qwertzguy said...

Argh Blogger sucks !
In my previous comment it removed the type specifier for Model:
new AttributeModifier("class", new Model[String]("style1"));
(so again replace [ and ] by < and >)