Sometimes we need to dynamically generate some part of the UI in a way that is difficult or impossible to achieve using the XHTML. In those cases, we can use the JSF binding feature to generate the JSF component on-the-fly using the Java code.
Also, RichFaces, being a standard JSF framework, gives the support for component binding.
Component binding, sometimes, is very useful to use complex logic to dynamically generate UI components in order to achieve some specific task. You can see it as the Swing GUI programming (as you know, JSF is also a component-based framework), but into the web context.
It's very important that you use the binding feature only if strictly necessary, as it makes the view depending on the application logic.
If you are packaging your project into an EAR structure, you might have some problem with the class loader.
In those cases (and if you have generated your project using seam-gen), just follow these simple steps:
/deployed-jars-war.list
file and copy all the content /deployed-jars-ear.list
file and paste all the copied content /deployed-jars-war.list
file /build.xml
file and delete the following code from the war
file:<copy todir="${war.dir}/WEB-INF/lib"> <fileset dir="${lib.dir}"> <includesfile name="deployed-jars-war.list"/> <exclude name="jboss-seam-gen.jar"/> </fileset> </copy>
/view/META-INF/
directory MANIFEST.MF
and insert the code:Class-Path: lib/
Now, all of your library files are in the lib
directory of the EAR, and there will be no problem with the class loader while using the binding feature with RichFaces and Seam.
Now that our environment is ready, we can create a simple example.
A very important thing to keep in mind is that you cannot use Seam conversational components to contain binding properties, because they are updated during the Restore View phase that occurs before the restoring of the Seam conversation context. You can see it in the Seam life cycle diagram shown in the next figure:
Another limitation of JSF component binding using the Seam framework is that you also can't inject conversational components inside EVENT
scoped ones.
One solution you can adopt is to use the @Factory
annotation (or, the @Out
or @Unwrap
annotations) to create a non-conversational component, which acts as a binding for the JSF object we need to customize.
The XHTML code for our example is very simple; let's add it to a file called /view/examples/binding/bindingExample.xhtml:
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:rich="http://richfaces.org/rich" template="/layout/template.xhtml"> <ui:define name="body"> <rich:panel binding="#{myPanel}" /> </ui:define> </ui:composition>
Also, let's create a bindingExample.page.xml
file in the same directory to initiate the conversation:
<?xml version="1.0" encoding="UTF-8"?> <page xmlns="http://jboss.com/products/seam/pages" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.1.xsd" login-required="true"> <begin-conversation join="true"/> <rewrite pattern="/bindingExample"/> </page>
The login is required as we are going to use GroupsListeHelper
that needs a logged user.
The bean (book.richfaces.advcm.modules.main.examples.binding. BindingExampleHelper)
contains just a method that creates the object we need in the EVENT
scope:
package book.richfaces.advcm.modules.main.examples.binding; @Name("bindingExampleHelper") @Scope(ScopeType.CONVERSATION) public class BindingExampleHelper { @In(create = true) GroupsListHelper groupsListHelper; @Factory(value = "myPanel", scope = ScopeType.EVENT, autoCreate = true) public UIPanel createPanel() { FacesContext facesContext = FacesContext.getCurrentInstance(); // Setting up the new panel UIPanel myPanel = new HtmlPanel(); myPanel.setId("myPanel"); myPanel.setHeader("Panel title"); // A simple text HtmlOutputText txt = new HtmlOutputText(); txt.setValue("My panel text.<br/>"); txt.setEscape(false); myPanel.getChildren().add(txt); // Adding the groups names for (ContactGroup group : groupsListHelper.getGroups()) { // Ading the group name to the panel txt = new HtmlOutputText(); txt.setValue(group.getName()+"<br/>"); txt.setEscape(false); myPanel.getChildren().add(txt); } HtmlOutputText latestTxt = new HtmlOutputText(); component bindingexamplelatestTxt.setValue("Latest panel text.<br/>"); latestTxt.setEscape(false); myPanel.getChildren().add(latestTxt); // An Ajax link UIAjaxCommandLink link = new HtmlAjaxCommandLink(); link.setValue("do something"); link.setAjaxSingle(true); link.setReRender("myPanel"); link.setActionExpression(facesContext.getApplication(). getExpressionFactory().createMethodExpression(facesContext. getELContext(), "#{someBean.someAction}", Void.TYPE, new Class[0])); // Adding the children (1 string and 1 link) myPanel.getChildren().add(link); return myPanel; } }
The myPanel
object (its type is UIPanel)
is created and put in EVENT
scope by the factory method createPanel()
it sets up the panel header and then creates some components (reading the groups list from the database) and adds them as children.
As you can notice, the "manager" Seam component (BindingExampleHelper
) is conversational, but produces an EVENT
scoped object.
18.227.52.7