02
Jan
10

User Interactions with JSF Forms


This page is about JSF Managed Beans and Forms. Its about how to break up the form submission process to handle large amount of fields. We will also cover how to avoid having a Flat Bean with only String based attributes. Instead we will create create a domain rich bean that will be easy to understand and maintain in the long run. We will cover techniques of creating/reading/updating/deleting these sub-beans. We will also cover a technique of cleaning up session beans once they are no longer needed.

  • Accept and validate large amount of data in multiple steps wizard approach.
  • Managed Beans and how handle sub-entities
  • Cleaning up session after completing a workflow

Managed Beans

JSF Managed beans hold data that is submitted by the user. Each field is an attribute of the managed bean. The submit buttons on the form can execute methods on the managed bean. The methods don’t need any arguments since the managed bean already contains the input elements of the form. Managed beans are not shared between users of the web application. Managed Beans have different types of scopes but the request and session scope are the most popular.

Large Forms

JSF forms are represented by Managed Beans. Sometimes forms get quite large and should be broken up into smaller chunks. Forms can be broken up into multiple pages by setting the scope to session and just having the pages bind to only a part of the Managed Bean. Provide “previous” and “next” buttons for user navigation. The “previous” buttons should not validate the form. You can do this by specifying immediate=’true’ in the command button. In general if you don’t want the page to get validated you can specify this attribute. Since validation is handled on a page by page basis you don’t need to worry about the step number like you did in the struts 1 framework.

Adding Sub-Beans to the Managed Bean

Another method of dealing with large forms is to break the backing bean into smaller chunks. This is where sub-beans and the Java Collections framework comes in handy. A typical case for this is when you have a bean that holds the user’s entire annual tax return. There is an area in the form where you specify zero one or many dependants. This is a good opportunity to use a Dependant Bean to hold each dependant and have a dependentList that is responsible for holding a list of them. All this can be maintained by the main tax Return Managed Bean. (see below)

	private Dependant dependant = new Dependant();
	private List<Dependant> dependantList = Dependant.getSample();

As you can see above we have a dependant, and a dependantList. One holds the information that was submitted by the user and the other holds the collection of dependents that was submitted so far.

One of the effective methods of allowing the user to add sub-beans is by presenting the user with a table and an add button. The table would contain a summary of already present sub-beans and allow the user to add more. At this point there are two options. 1) present the user with another page and have them enter the information or 2) have them enter the information on a popup window or similar. Once the user submits, validate and add the information to the main Bean. In this model the sub-bean plays the role of the data structure. None of the action methods are executed on the sub-bean.

When the user clicks add we do the following:

public String addDependant() {
	System.out.println("Adding dependant to list.");
	dependantList.add(dependant);
	// assign a new dependent object for the next submission.
	dependant = new Dependant();
	return "success";
}

The highlighted line is necessary since we are adding a reference to the user’s submitted form we don’t want the form that is subitted after this one to have the same reference. Hence we instantiate a new Dependent object for the next form submission.

Reading / Editing / Deleting Sub Entities

The system needs to know what the user clicked. The HtmlDataTable class is an extension to the dataTable component that the user is interacting with. When the user clicks a link, the component knows what data item the link was clicked for. The action handling method of the main bean needs to get the object and inspect it for further processing. In order for all this to work we need to “bind” the dataTable with the HTMLDataTable class in the managed Bean.

Binding to HTMLDataTable

The “binding” attribute is used to bind the dataTable to the HtmlDataTable attribute of the Managed Bean.

<h:dataTable border="1" value="#{taxReturn.dependantList}"  var="dependantrow" binding="#{taxReturn.dependantTable}">
<!--jsf column elements go here.-->
</h:dataTable>

In the TaxReturn has the following defined as an attribute.

private HtmlDataTable dependantTable;

Action Column

<h:column id="action_column">
<f:facet name="header"><h:outputText id="text6" value="action"></h:outputText></f:facet>
<h:commandLink id="remove" action="#{taxReturn.removeDependant}" immediate="true">
<h:outputText value="remove"></h:outputText>
</h:commandLink>
</h:column>

In the following code example shows the Dependant Bean being removed from a list of Dependant Objects.

public String removeDependant() {
	System.out.println("Removing dependant");
	Dependant dependantToRemove = (Dependant) dependantTable.getRowData();
	dependantList.remove(dependantToRemove);
	return "refresh";
}

Note: it is important to implement the equals() and hashCode() in order for this to work. Since the “business” key is used to identify if the objects are equal we don’t need to evaluate each and every field to determine equality. See my other page on implementing equals and hashcode.
Here is the equals and hashcode implementation.

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((ssn == null) ? 0 : ssn.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Dependant other = (Dependant) obj;
		if (ssn == null) {
			if (other.ssn != null)
				return false;
		} else if (!ssn.equals(other.ssn))
			return false;
		return true;
	}

JSF Managed Bean Session Cleanup

Once a JSF workflow is complete and the managed bean is in the session it should be cleaned up. Otherwise the object will stay around until the session expires. On a high volume website this can take up precious memory. To cleanup the session the Managed bean should execute the following.

public String processAndCleanup() {
	ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
	Map map = externalContext.getSessionMap();
	map.remove("taxReturn"); // the name of the jsf managed bean.
	return "success";
}

The only drawback with this approach I see, and it might not be a big deal is that the Managed Bean is aware of the ExternalContext which is a JSF artifact. If you have a better way to do this please comment below.

Snoop Servlet

During development you may verify that the bean is out of the session by viewing the output of the SnoopServlet.

Thats all for now!

Advertisements

1 Response to “User Interactions with JSF Forms”


  1. October 2, 2014 at 3:02 pm

    Do you have entire code that I could test and play with? github or somewhere else?


Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


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

Join 75 other followers

January 2010
S M T W T F S
« Dec   Feb »
 12
3456789
10111213141516
17181920212223
24252627282930
31  

Blog Stats

  • 813,774 hits

%d bloggers like this: