本文的目的与上一篇文章相同 - 涵盖 RichFaces 中经常在 RichFaces 用户论坛 上提出的一些特定组件问题。一些观点(也许所有观点)你可能已经知道... 但不要忘记,每个人有时都是从零开始的 :) 因此,我的目的是通过一些类似这样的启动样本来帮助刚开始使用 RichFaces 的朋友们。
在这里,我将创建一个简单的搜索/结果表单。让我们假设每个搜索结果对象都包含大量类似信息,应该完全显示。因此,我们将使用 标签式结果表示。
从一开始,我们就创建了一个具有 RichFaces 支持的简单项目。我使用了 JSF 1.2、Facelets 1.1.14 和 RichFaces 3.3.1,并在 Tomcat 6 下部署。简单项目创建的过程在 RichFaces 开发者指南。第3节 中有详细描述。
如果你已经访问过我们的 richfaces-demo,你可能在许多示例中看到了简单的 首都 对象列表(建议框、表格排序示例 等...)。因此,让我们重用现有 Java 代码。只需下载 类 和 资源,并将其放置在创建的项目中的一些源包中。然后在 faces-config 中注册 CapitalsBean。
<managed-bean> <managed-bean-name>capitalsBean</managed-bean-name> <managed-bean-class>org.richfaces.demo.capitals.CapitalsBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean>
查看JavaBean代码。我们有一个包含所有首都的首都列表。我们需要添加一个额外的列表来存储满足搜索条件的首都。让我们称它为foundCapitals。同时,我们还需要添加一个属性来存储搜索条件。在这种情况下,我使用了简单搜索,通过首都名称使用startsWith方法。因此,接下来需要添加的代码如下:
private ArrayList<Capital> foundCapitals = new ArrayList<Capital>(); private String searchValue = ""; // Do not forget to add getters and setters
现在是时候为这种情况工作在页面源代码了。接下来的部分代表一个搜索面板。

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:a4j="http://richfaces.org/a4j" xmlns:rich="http://richfaces.org/rich" xmlns:c="http://java.sun.com/jstl/core"> <h:form> <rich:panel header="Simple Search"> <h:outputText value="Enter the first letters of the capitals:" /> <h:inputText id="searchField" value="#{capitalsBean.searchValue}"/> <rich:hotKey selector="##{rich:clientId('searchField')}" key="return" handler="#{rich:element('search')}.onclick();return false;"/> <a4j:commandButton action="#{capitalsBean.search}" value="Search" reRender="output" id="search"/> </rich:panel> </h:form> </ui:composition>
在那里,我想引起你注意的组件是rich:hotKey。它实现了当用户在输入中按下Enter键时发送ajax请求的常见需求。#{rich:clientId}函数返回要附加热键的搜索输入的clientId。并且当在输入中按下Enter键后,将通过在handler属性中定义的JS(#{rich:element}通过其Id返回按钮DOM元素)来点击搜索按钮。
现在让我们定义应该使用foundCapitals列表动态创建的tabPanel。

请在面板代码之后添加以下代码
<a4j:outputPanel id="output"> <rich:tabPanel id="tapPanel" width="700" rendered="#{not empty capitalsBean.foundCapitals}"> <c:forEach items="#{capitalsBean.foundCapitals}" var="cap"> <rich:tab name="#{cap.name}" > <f:facet name="label"> <h:panelGrid columns="2"> <h:outputText value="#{cap.name}" /> <h:graphicImage value="/images/icons/delete.gif" style="width:12px; height:12px;" onclick="myFunc('#{cap.name}'); Event.stop(event);"/> </h:panelGrid> </f:facet> <h:panelGrid columns="2" style="margin:20"> <h:outputText value="State Name" /> <h:inputText value="#{cap.state}" /> <h:outputText value="State Capital" /> <h:inputText value="#{cap.name}" /> <h:outputText value="State TimeZone" /> <h:inputText value="#{cap.timeZone}" /> </h:panelGrid> </rich:tab> </c:forEach> </rich:tabPanel> <h:outputText value="No active search results." style="font-style:italic" rendered="#{empty capitalsBean.foundCapitals}"/> </a4j:outputPanel> <a4j:jsFunction action="#{capitalsBean.remove}" name="myFunc" ajaxSingle="true" reRender="output"> <a4j:actionparam name="current"/> </a4j:jsFunction>
以下要点需要强调:我们将使用c:forEach来动态创建标签。这是RichFaces新手经常犯错的地方。你不能使用重复组件(既不是ui:repeat也不是a4j:repeat),因为它们在页面渲染时间工作,并且不会在JSF树中创建组件,只是迭代相同的实例。我们应该使用c:forEach标签,它在视图构建阶段工作,并导致实际标签组件被添加到JSF树中。有关更多详细信息,请参阅c:forEach与ui:repeat在Facelets中的比较文章。
在c:forEach内部,我们定义了一个标签,其内容依赖于迭代变量的属性。每个标签将包含使用搜索找到的每个首都对象的信息。
标签面包含标签的文本标签和调用带当前标签名称参数的jsFunction的关闭控制。因此,a4j:jsFunction将在移除控制被点击后引发ajax请求,并将该标签的首都名称通过actionparam放入请求参数。
在标签移除和搜索之后,我们应该更新标签面板并渲染标签,如果找到对象或如果没有结果则显示某些标签。正如你所看到的,我们正在使用rendered属性在tabPanel和outputText组件上定义根据是否找到某些对象应该渲染什么。还有一个地方需要强调RichFaces的限制之一。我们不应该直接条件性地重新渲染条件性渲染的元素(outputText和tabPanel)。RichFaces的Ajax机制不允许插入任何内容。我们应该更新一些现有的DOM节点。a4j:outputPanel应该添加在条件性渲染元素周围,我们将更新这个outputPanel。
最后一步是实现我们的CapitalsBean中的搜索和移除方法。
public void search() { foundCapitals.clear(); for (Capital currentCapital : capitals) if (currentCapital.getName().startsWith(searchValue)) foundCapitals.add(currentCapital); } public Capital getCapitalIdByName(String name) { for (Capital currentCapital : capitals) { if (currentCapital.getName().equals(name)) return currentCapital; } return null; } public void remove() throws Exception { Capital currentCapital = getCapitalIdByName(FacesContext .getCurrentInstance().getExternalContext() .getRequestParameterMap().get("current")); if (null != currentCapital) foundCapitals.remove(currentCapital); else throw new Exception("capital name parameter is null"); }
现在让我们部署应用程序并启动服务器以查看结果。
没有找到结果
带有结果的标签面板

我希望在RichFaces使用中应该注意的一些细节,这些细节已经在我们的文档中呈现,并在本文中再次强调,将帮助开发者减少构建类似功能所需的时间。