Pages

Saturday, November 22, 2008

Vertically formatted CHECKBOXLIST - struts 2

This is one tricky point encountered by myself when creating
checkboxlist with struts 2. The default 'xhtml' them will always rendered
horizontally formatted list into the page. To have vertically formatted checkboxlist, we have to overwrite the default FreeMarker template for checkboxlist component.
If you check carefully, you can find the set of templates files
written in FreeMarker for each theme of struts 2 from struts-core.jar file inside the template folder. Here, I am going to overwrite the template file for checkboxlist component to have vertically formated checkboxlist.
Consider fallowing HTML mark up rendered into the view page from
checkboxlist component. It tries to list the users of the system preceding with a checkbox. User id has been set as the value of each checkbox.


<input type="checkbox" id="users-1" value="1000" name="users"/>
<label class="checkboxLabel" for="users-1">administrator</label>
<input type="checkbox" id="users-2" value="1001" name="users"/>
<label class="checkboxLabel" for="users-2">siriwardana</label>

You will get the fallowing out put.

This is a mark up of horizontally formated checkboxlist. If we can add additional '<br>' tag after each of this <label> tag, we are done !. We can have a vertically formatted checkboxlist. We have to overwrite checkboxlist.ftl file located at template/xhtml in struts-core.jar file. I do not suggest you to change this file. Instead, we will create a new theme. To create a new our own theme, create a folder called 'template' under /WEB-INF/classes. Then create a folder with new theme name. In my case, I created a folder called 'pda' and copied all the template files from default xhtml folder to pda folder. Now, I am going to change the checkboxlist.ftl file located at pda folder.

We will look at the contents of this file for a moment.

<#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />
<#include "/${parameters.templateDir}/simple/checkboxlist.ftl" />
<#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" /><#nt/>

This is written in FreeMarker. I guess, now you know what we have to do is. You can see, this has included checkboxlist.ftl file from default simple theme. We have to edit that file. Again, I am going to overwrite the default simple theme comes with struts 2 for my new theme. I am creating a folder called "pda_simple" under the /WEB-INF/classes/template and copy the checkboxlist.ftl file from default simple theme folder to pda_simple folder. Before edit this checkboxlist.ftl file, we have to change the file path of checkboxlist.ftl file located at pda folder as fallows.



<#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />
<#include "/${parameters.templateDir}/pda_simple/checkboxlist.ftl" />
<#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" /><#nt/>

Now this refers checkboxlist.ftl file from our new simple theme which is pda_simple. To control the alignment of our checkboxlist component, I am going to use the cssStyle attribute of the checkboxlist component. Here is the my view code.


<s:form action="deleteUser" method="POST" theme="pda">
<s:checkboxlist list="users" name="users" listKey="userId"
listValue="userName" cssStyle="vertical">
</s:checkboxlist>
<s:submit value="update"></s:submit>
</s:form>




From above code, I want your attention on theme attribute of form component and the cssStyle attribute of checkboxlist component. I have specified our new theme for current form and cssStyle is set to vertical to have a vertically formatted checkboxlist.
Now, we have to edit checkboxlist.ftl file located at /WEB-INF/classes/template/pda_simple as fallows.


<#assign itemCount = 0/>
<#if parameters.list?exists>
<@s.iterator value="parameters.list">
<#assign itemCount = itemCount + 1/>
<#if parameters.listKey?exists>
<#assign itemKey = stack.findValue(parameters.listKey)/>
<#else>
<#assign itemKey = stack.findValue('top')/>
</#if>
<#if parameters.listValue?exists>
<#assign itemValue = stack.findString(parameters.listValue)/>
<#else>
<#assign itemValue = stack.findString('top')/>
</#if>
<#assign itemKeyStr=itemKey.toString() />
<input type="checkbox" name="${parameters.name?html}" value="${itemKeyStr?html}" id="${parameters.name?html}-${itemCount}"<#rt/>
<#if tag.contains(parameters.nameValue, itemKey)>
checked="checked"<#rt/>
</#if>
<#if parameters.disabled?default(false)>
disabled="disabled"<#rt/>
</#if>
<#if parameters.title?exists>
title="${parameters.title?html}"<#rt/>
</#if>
<#include "/${parameters.templateDir}/simple/scripting-events.ftl" />
<#include "/${parameters.templateDir}/simple/common-attributes.ftl" />
/>
<label for="${parameters.name?html}-${itemCount}" class="checkboxLabel">${itemValue?html}</label>
<#if parameters.cssStyle?exists>
<#if "${parameters.cssStyle?html}" == "vertical">
<br><#rt/>
</#if>
</#if>
</@s.iterator>
<#else>
&nbsp;
</#if>



Actually you don't need to worry about the whole code above, but what I have highlighted. At the very beginning, I mentioned my target is adding additional <br> tag at the end of each <label> tag. I have done. There may be better ways of achieving this. This is how, I got through this. Finally, I got the expected output as fallows.


The CHECKBOXLIST component - struts 2

This a vary usefull UI component comes with struts 2 which allows user
for multiple selection. If we use normal HTML checkbox component, we have to write a custom function to get the selected values from a list of check boxes. Struts 2 provides a convenience way of fetching selected from a list of check boxes. Struts 2 ValueStack will resolve an array of string for the selected check boxes.


I will further demonstrate this with a simple example. Suppose I want to create a check box list which allows user to select several users from the list. This is my User class.

public class User{
private int userId,
privte Stirng userName;

// -------
}

Then I should create the HTML markup for the component.

<s:form action="deleteUser" method="POST" >
<s:checkboxlist list="users" name="users" listKey="userId"
listValue="userName">
</s:checkboxlist>
<s:submit value="update"></s:submit>
</s:form>

Here, the value of list attribute "users" should be prepopulated with an action class, and then that action class should result into this page. Don't be confuse, I have use same for the value of the name attribute. You can use any meaningful one for this. Then you have to write the action class to fetch the checked list as fallows.

package com.axiohelix.pda.actions;

import com.opensymphony.xwork2.ActionSupport;

public class DeleteUser extends ActionSupport{
private String[] users;

public String[] getUsers() {
return users;
}
public void setUsers(String[] users) {
this.users = users;
}
public String execute(){
String[] userId = this.getUsers();
// --------------------------
return SUCCESS;
}
}

Sunday, November 9, 2008

The SELECT component - struts 2

The select component is perhaps the most common collection-based
UI component comes with struts 2. In a java web application, it's common to build these list of options from a Collection, Map or Arrays of data. The fallowing snippet shows the simplest use case of the select UI component.


<s:select name="userType" list="{'Administrator','Power User','Guest'}" />

Here, we have supplied an OGNL list literal as the list value of the select box. This render the fallowing HTML markup into the page.

<select name="userType" id="registerUserForm_userType">
<option value="Administrator">Administrator</option>
<option value="Power User">Power User</option>
<option value="Guest">Guest</option>
</select>

Here, "registerUserForm" is the my action name submitted with the form. But, most of the time, we may need to create select UI component with more advance Collection data. In this case, it may be list of UserType objects. Suppose, we have a class as fallows.

public class UserType{
private int userTypeId,
private String userTypeName,
// .....
}

Now, we want to create the select UI component from a List of UserType objects. In this case, we need to have userTypeId as the value and userTypeName as option contents (what user can see from select box). Here, the userTypeId should be a key attribute in the matching database table.

<s:select list="userType" key="userType" listKey="userTypeId"
listValue="userTypeName">

</s:select>
userType is the list of UserType objects which is already exposed into the ValueStack through an action class. listKey and listValue are important tow attributes, when it comes to this kind advance data types.

  • listKey - The property of the List’s elements to be used for the value submitted when those elements are complex types; key by default.
  • listValue - The property of the List’s elements to be used for the content of the option when those elements are complex types in other words, the string seen by the user; value by default.

Here is the rendered HTML from the above UI components.

<select id="registerUserForm_userType" name="userType">
<option value="1">administrator</option>
<option value="2">power</option>
<option value="3">guest</option>
</select>

Saturday, November 8, 2008

Using global messages - struts 2

Putting text resources in properties files is a common web
application development practice enhancing proper management of texts,easy modifications and for internationalization. When it comes to struts 2, it further helps to keep our code clean and reduce the development time. To use global messages with struts 2, we need to create "global-messages.properties" and place it on the class path at WEB-INF/classes. All the messages can be put in this file as key- value pairs.


//.....
userName=User Name
password=Password
//.....
In order to use this file, we have to tell struts 2 where to find this file. As usual , we need to add one entry into the "struts.properties" file residing in the class path.

//.....
struts.custom.i18n.resources=global-messages
//.........

Here, how we use these messages in our view pages. You have to use the "key" attribute of UI components to specify the key from the global-messages.

<s:textfield key="userName"/>
<s:password key="password"/>

Key attribute does infer the name and value for the text filed with message key. Here, proper naming convention is important to have this kind of service from the struts 2 framework.

Sunday, November 2, 2008

Changing the "theme" of UI components - struts 2

The struts 2 UI components come with four themes for rendering HTML markup into your view page.

  • simple
  • xhtml
  • css_xhtml
  • ajax
The default theme coming with struts 2 is xhtml which is involving html table layout to render the form component in the view page. For example consider the fallowing UI components.

<s:form action="doLogin.action" method="POST">
<s:textfield name="userName" label="User name" />
</s:form>

This UI components will render the fallowing HTML markup into your view page base on the default theme of the struts 2. You may confuse, if you haven't heard about struts 2 themes.

<form method="post" action="doLogin.action" onsubmit="return true;" id="doLogin">
<table class="wwFormTable">
<tbody>
<tr>
<td class="tdLabel">
<label class="label" for="doLogin_userName">User name:</label>
</td>
<td>
<input type="text" id="doLogin_userName" value="" name="userName"/>
</td>
</tr>
</tbody></table>
</form>
This HTML markup was rendered into view page on xhtml theme of struts 2. You may probably want to change the default theme. You can change this by overriding the default property which is defined in default.properties, found in struts 2 core jar file at org.apache.struts2.

To override any of the framework’s default properties, you only need to create your own properties file, named struts.properties, and place it in the classpath. To change the default theme, just create a struts.properties file with the following property definition:
struts.ui.theme=css_xhtml

In addition to these four themes that comes with struts 2, you can create your own them too.

Saturday, November 1, 2008

Filtering and Projecting with OGNL - struts 2

This is important OGNL feature when we are working with collections
to generate the UI components with Struts 2 tag libraries. To explain this, I will consider a class called "
Employee". Suppose we have a list of employee objects from the "ValueStack".

public class Employee{

private int age;

private String firstName;

private String lastName;

//......

}

Now, you want to filter out the employees where the age is grater than 30. The OGNL filtering will resolve the problem. You can get this as fallows .

<s:set name="empList" value="employeeList.{?#this.age > 30}"></s:set>
<s:iterator value="#empList">
<s:property value="firstName"/>
</s:iterator>

Here, #this refers to the "employeeList" which is resolved in "ValueStack". That is it, about filtering. Now I will explain, how we use the projection. Think, you want to have a separate list with employee's full name. The OGNL projection feature will lead us to achieve it .

<s:set name="empNameList"
value="employeeList.{firstName + ' ' + lastName}"></s:set>
<s:iterator value="#empNameList" status="stat">
<s:property value="#empNameList[#stat.getIndex()]"/>
</s:iterator>

Share

Widgets