Friday, August 3, 2012

Build Time is the time when components are added to the tree declaratively (using facelet) or programmatically. In JSF, the code is like this parentComponent.getChildren().add(childComponent). These codes are called to construct a UI component tree. At the Render time, the rendering engine converts your component tree into HTML which is displayed by browser.

Usually, there is one-to-one correspondence between component and backing bean value. For example, you have one UIInput for user name, and one UIInput for password. So each form input in browser side has a match in server component. For these kinds of components, you really do not need to understand what are build time and render time. Programmatically, you can hookup your component with backbean directly. For example,

Here the beanForThisInput is an object associated with this input. This piece of code establishes their relationship by attaching the beanForThisInput to input attributes. You can aslo attach actionListener like this

UIData(HtmlDataTable and ui:repeat) is the exceptional to this rule. Suppose a data table is used to display the user name for 10 users. The user name is displayed through a UIOutput component. So the tree structure is like this UIData->UIColumn->UIOutput. There is only one UIColumn component. Under UIColumn there is only one UIOutput although there are 10 user names for display. In the build time, the code is like this UIColumn.getChildren().add(UIOutput). This piece code runs only once so UIColumn has only one UIOutput component. At the render time, the UIComlumn->UIOutput will be rendered 10 times: one for each user name. At build time, you could give a value to UIOutput like this:UIOutput.setValue(user.getName());However, this approach does not work for component under UIData. Why?

First, this code is called at build time only once. It of course does not work for 10 user names.
Second, when it comes to renderer time, the control is passed to renderkit. There is no hook to 1) pass you the current user and let you call setValue programmatically. Remember, this piece of code is called 10 times, one time for each user.

For component tree under UIdata, the tree is like a template. The template will be looped multiple times. So how can you set the value for UIOutput correctly? Find the current object from the context. The context is provided by UIData through "var" variable.

This solution works. Unfortunately, it looks odd to programmer from Swing. In Swing, there is no expression language. Object connects each other through method call. Of course, In Swing, there is no mechanism to construct the UI declaratively, either.

First, give the button an ID explicitly. This may be a bug in JSF RI implementation. if you want to know more, go here.

Second, the ajax "execute" attribute should include "@this". "@this" keyword informs the server that it should process the button and issues action event to this button. Otherwise, any event listener including ajax event listener will not be called.

Third, attach the ajax vehavior to button as b.getDefaultEventName() which is "action". I first attached it as "click". "click" is a client-side event name. The logic event name for action is "action", not "click". This is automatically if xhtml file is used.