TabPanel with switchType
sandman202 Apr 25, 2009 8:08 AMI have a detail user screen called Uzer.xhtml. At the bottom of the screen are 2 tabs. The first is a phone number listing and the second is an address listing.
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:s="http://jboss.com/products/seam/taglib" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:a4j="http://richfaces.org/a4j" xmlns:rich="http://richfaces.org/rich" template="/layout/template.xhtml"> <ui:define name="body"> <rich:panel> <f:facet name="header">User Details</f:facet> <s:decorate id="companyDecoration" template="/layout/display.xhtml"> <ui:define name="label">Company</ui:define> <h:inputText id="company" size="50" maxlength="50" disabled="true" value="#{uzerHome.instance.company}"> <a4j:support event="onblur" reRender="companyDecoration" bypassUpdates="true"/> </h:inputText> </s:decorate> <s:decorate id="nameDecoration" template="/layout/display.xhtml"> <ui:define name="label">Name</ui:define> <h:inputText id="name" size="40" maxlength="40" required="true" disabled="true" value="#{uzerHome.instance.name}"> <a4j:support event="onblur" reRender="nameDecoration" bypassUpdates="true"/> </h:inputText> </s:decorate> <s:decorate id="emailDecoration" template="/layout/display.xhtml"> <ui:define name="label">Email</ui:define> <h:inputText id="email" size="40" maxlength="40" disabled="true" value="#{uzerHome.instance.email}"> <a4j:support event="onblur" reRender="emailDecoration" bypassUpdates="true"/> </h:inputText> </s:decorate> ... <div style="clear: both" /> </rich:panel> <div class="actionButtons"> <s:button view="/role/admin/UzerEdit.xhtml" id="edit" value="Edit" /> <s:button view="#{empty uzerFrom ? '/role/admin/UzerList' : uzerFrom}.xhtml" id="done" value="Done" /> </div> <rich:tabPanel switchType="ajax"> <rich:tab label="Phone Numbers"> <a4j:include viewId="/role/admin/PhoneTable.xhtml"> <ui:param name="phoneFrom" value="/role/admin/Uzer"/> </a4j:include> <div class="actionButtons"> <s:button id="addPhone" value="Add Phone Number" view="/role/admin/PhoneEdit.xhtml"> <f:param name="uzerId" value="#{uzerHome.instance.id}" /> <f:param name="phoneFrom" value="/role/admin/Uzer" /> </s:button> </div> </rich:tab> <rich:tab label="Addresses" immediate="false"> <a4j:include viewId="/role/admin/AddressTable.xhtml" > <f:param name="addressListSort" value="address.type"/> <f:param name="addressFrom" value="/role/admin/Uzer"/> </a4j:include> <div class="actionButtons"> <s:button id="addAddress" value="Add Address" view="/role/admin/AddressEdit.xhtml"> <f:param name="uzerId" value="#{uzerHome.instance.id}" /> <f:param name="addressFrom" value="/role/admin/Uzer" /> </s:button> </div> </rich:tab> </rich:tabPanel> </ui:define> </ui:composition>
The PhoneTable.xhtml and AddressTable.xhtml are similar so I will only show AddressTable.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:s="http://jboss.com/products/seam/taglib" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:a4j="http://richfaces.org/a4j" xmlns:rich="http://richfaces.org/rich"> <a4j:form id="addressTableForm"> <div class="association" id="addresss"> <h:outputText value="No address exists" rendered="#{empty addressList.resultList}"/> <rich:dataTable id="addressList" var="_address" value="#{addressList.resultList}" rendered="#{not empty addressList.resultList}" rows="25"> <rich:column rendered="#{addressFrom eq '/role/admin/AddressList'}"> <f:facet name="header"> <s:decorate template="/layout/sort.xhtml"> <ui:param name="entityListName" value="addressList"/> <ui:param name="entityList" value="#{addressList}"/> <ui:param name="propertyLabel" value="Name"/> <!-- doesn't support two sort fields --> <ui:param name="propertyPath" value="uzer.name"/> </s:decorate> </f:facet> <s:link id="view" value="#{_address[1].name}" view="/role/admin/Uzer.xhtml" propagation="none"> <f:param name="uzerFrom" value="/role/admin/AddressList"/> <f:param name="uzerId" value="#{_address[1].id}"/> </s:link> </rich:column> <rich:column> <f:facet name="header"> <s:decorate template="/layout/sort.xhtml"> <ui:param name="entityListName" value="addressList"/> <ui:param name="entityList" value="#{addressList}"/> <ui:param name="propertyLabel" value="Type"/> <!-- doesn't support two sort fields --> <ui:param name="propertyPath" value="address.type"/> </s:decorate> </f:facet> #{_address[0].type} </rich:column> ... <rich:column> <f:facet name="header">Action</f:facet> <s:link view="#{empty from ? '/role/admin/Address' : from}.xhtml" value="Select" id="addressSelect" propagation="none"> <f:param name="addressFrom" value="#{addressFrom}"/> <f:param name="addressId" value="#{_address[0].id}"/> </s:link> </rich:column> <f:facet name="footer"> <rich:datascroller pageIndexVar="pageIndex" pagesVar="pages" maxPages="25"/> <ui:remove> <rich:datascroller pageIndexVar="pageIndex" pagesVar="pages" boundaryControls="hide" stepControls="hide" fastControls="show"> <f:facet name="pages"> <h:outputText style="whitespace: nowrap" value="Page #{pageIndex} of #{pages}"></h:outputText> </f:facet> </rich:datascroller> </ui:remove> </f:facet> </rich:dataTable> </div> </a4j:form> </ui:composition>
The addressList.java
@Name("addressList") public class AddressList extends EntityQuery<Address> { private static final long serialVersionUID = 7154978428753938951L; private static final String[] RESTRICTIONS = { // tab list selection "address.uzer.id = #{uzerHome.uzerId}", // non-tab list selection "address.type = #{addressList.address.type}", "lower(address.addressee1) like concat('%',lower(#{addressList.address.addressee1}),'%')", "lower(address.addressee2) like concat('%',lower(#{addressList.address.addressee2}),'%')", "lower(address.address1) like concat('%',lower(#{addressList.address.address1}),'%')", "lower(address.address2) like concat('%',lower(#{addressList.address.address2}),'%')", "lower(cityStateZip.city) like concat('%',lower(#{addressList.cityStateZip.city}),'%')", "lower(cityStateZip.province) like concat('%',lower(#{addressList.cityStateZip.province}),'%')", "lower(cityStateZip.zipcode) like concat('%',lower(#{addressList.cityStateZip.zipcode}),'%')", }; private Address address = new Address(); private CityStateZip cityStateZip = new CityStateZip(); public AddressList() { this.setEjbql("select address, uzer, cityStateZip from Address address join address.uzer uzer join address.cityStateZip cityStateZip"); this.setRestrictionExpressionStrings(Arrays.asList(RESTRICTIONS)); } public Address getAddress() { return address; } public CityStateZip getCityStateZip() { return cityStateZip; } }
As you can see, my approach is similar to that described in "Seam in Action".
On the tabPanel in Uzer.xhtml, when I define the switchType to client, the SQL for both tabs are loaded when the Uzer.xhtml is displayed. Switching between the 2 tabs does not reread the data from the database. When I change the switchType to either server(default) or ajax, the SQL for both tabs are loaded when the Uzer.xhtml is displayed. However, switching between the 2 tabs causes both tabs to reload the data from the database.
1. Is this supposed to happen this way? This seems to be very ineffecient. I would of expected only the active tab to load the data and only load it once.
2. When I unclude PhoneTable.xhtml and AddressTable.xhtml, is it possible to also have a PhoneTable.page.xml and AddressTable.page.xml? When I try this approach, it appears to not even look at the xml's. I have to place the params in my Uzer.page.xml.