Building JSPs and their associated ManagedBeans that can handle dynamic lists and tables is a bit of a challenge. The task is simplified by several tags included as part of Tomahawk along with the support classes they require. Useful tags include <t:dataList> and <t:dataTable>.
Several examples are shown below.
The first displays a dynamic list of links to support browsing over a hierarch of category names, shown as an expanding and contracting row of links:
Catalog > Tools
The second is a table, with only one column, that shows the possible subcategories for the last category in the list, shown above. Clicking on one of those links extends the row of links, above. the same basic logic can be used to build a multi-column table, such as one suitable for a table of products along with pictures of them, by using a faces grid.
Hammers
Saws
ScrewdriversTwo other examples show a table of products that might be found in an online catalog and an expansion of one such product in which additional detail is shown.
For each type of data, the discussion includes core code from the JSP and from the associated ManagedBean.
1. Define the JSP for a dynamic expanding list, to be shown horizontally:
<%@ taglib prefix="t" uri="http://myfaces.apache.org/tomahawk"%> . . . <h:form id="categoryPathForm"> <h4> <t:dataList id="categoryPathList" value="#{managedBeanCatalogBrowse.categoryPathList}" var="beanCategory" binding="#{managedBeanCatalogBrowse.categoryDataList}" layout="simple" rowCountVar = "count" rowIndexVar = "index" > <h:column> <h:commandLink action="#{managedBeanCatalogBrowse.actionExpandCategory}"> <h:outputText value="#{beanCategory.name}"/> <f:setPropertyActionListener target="#{managedBeanCatalogBrowse.categoryId}" value="#{beanCategory.categoryId}" /> </h:commandLink> <h:outputText value=" > " rendered="#{index+1 < count}" /> </h:column> </t:dataList> </h4> </h:form>2. Define the ManagedBean for the JSP In this example, the list is generated in the methods actionLoadCatalog and actionExpandCatalog.
import org.apache.myfaces.custom.datalist.HtmlDataList; import org.apache.myfaces.component.html.ext.HtmlDataTable; . . . // category path support private List categoryPathList = null; private HtmlDataList categoryDataList; private String categoryId = null; // product list support private List productList = null; private HtmlDataTable productTable; private String productId = null; . . . public String actionLoadCatalog() { // get admin user's role String roleAdmin = (String) session.getAttribute("role"); // instantiate models ModelCategoryAdmin modelCategoryAdmin = new ModelCategoryAdmin(); // reset lists support resetCategoryPathList(); resetCategoryChildrenList(); resetProductList(); resetProductExpandList(); // call model BeanCategory dataBeanNew = modelCategoryAdmin.getRoot( roleAdmin ); if ( !(dataBeanNew.isOk()) ) { // need to add error message return "browseCatalogAgain"; } else { //get and pass category path list CollectionBean collectionBeanCategoryPathLinks = new CollectionBean(); collectionBeanCategoryPathLinks.add(dataBeanNew); setCategoryPathList( collectionBeanCategoryPathLinks.getDataBeans() ); session.setAttribute( "collectionBeanCategoryPathLinks", collectionBeanCategoryPathLinks ); return "browseCatalogAgain"; } } public String actionExpandCategory() { // get admin user's role String roleAdmin = (String) session.getAttribute("role"); // instantiate models ModelCategoryAdmin modelCategoryAdmin = new ModelCategoryAdmin(); ModelProductAdmin modelProductAdmin = new ModelProductAdmin(); // reset lists support resetProductList(); resetProductExpandList(); BeanCategory dataBeanFind = new BeanCategory(); dataBeanFind.setCategoryId( categoryId ); BeanCategory dataBeanNew = modelCategoryAdmin.find( dataBeanFind, roleAdmin ); // test failure if ( ! dataBeanNew.isOk() ) { return "browseCatalogAgain"; } // update the category navigation resources, as necessary // test for interior category, prune if appropriate CollectionBean collectionBeanCategoryPathLinks = (CollectionBean) session.getAttribute("collectionBeanCategoryPathLinks"); BeanCategory beanCategoryLast = (BeanCategory) collectionBeanCategoryPathLinks.getBeanLast(); if ( ! ((dataBeanNew.getCategoryId()).equals(beanCategoryLast.getCategoryId()) ) ) { for (int i = 0; i < collectionBeanCategoryPathLinks.size(); i++ ) { beanCategoryLast = (BeanCategory) collectionBeanCategoryPathLinks.getBeanLast(); if ( ! ((dataBeanNew.getCategoryId()).equals(beanCategoryLast.getCategoryId()) ) ) collectionBeanCategoryPathLinks.remove(beanCategoryLast); else break; } } // save (possibly) updated category path links collectionBean and session.setAttribute( "collectionBeanCategoryPathLinks", collectionBeanCategoryPathLinks ); setCategoryPathList( collectionBeanCategoryPathLinks.getDataBeans() ); // get children, if any CollectionBean collectionBeanCategoryChildren = modelCategoryAdmin.getChildren( dataBeanNew, roleAdmin ); // test not leaf node ==> get categories int size = collectionBeanCategoryChildren.size(); if ( size > 0 ) { session.setAttribute("collectionBeanCategoryChildren", collectionBeanCategoryChildren); setCategoryChildrenList( collectionBeanCategoryChildren.getDataBeans() ); session.removeAttribute("collectionBeanProducts"); // else leaf node ==> get products } else { // get products for leaf category BeanProduct dataBeanProduct = new BeanProduct(); dataBeanProduct.setCategoryId( categoryId ); CollectionBean collectionBeanProducts = modelProductAdmin.search( dataBeanProduct, roleAdmin ); // add image url (for small image) for ( int i=0; i<collectionBeanProducts.size(); i++ ) { BeanProduct bean = (BeanProduct) collectionBeanProducts.getBeanNext(); int productId = bean.getProductId(); String imageType = bean.getImageTypeSmall(); String imageFileSmallUrl = Util.getImageUrl( productId, imageType, Constant.IMAGESMALL ); bean.setImageFileSmallUrl( imageFileSmallUrl ); } session.setAttribute( "collectionBeanProducts", collectionBeanProducts ); setProductList( collectionBeanProducts.getDataBeans() ); } return "browseCatalogAgain"; }3. Define the JSP for a dynamic expanding table:
<%@ taglib prefix="t" uri="http://myfaces.apache.org/tomahawk"%> . . . <h:form id="categoryChildrenForm"> <blockquote> <h4> <t:dataTable id="categoryChildrenTable" value="#{managedBeanCatalogBrowse.categoryChildrenList}" var="beanChild" binding="#{managedBeanCatalogBrowse.categoryChildrenTable}" renderedIfEmpty="false" > <h:column> <f:facet name="header"> <b><h:outputText value="Select Category" /></b> </f:facet> <h:commandLink action="#{managedBeanCatalogBrowse.actionAddCategorytoPath}"> <h:outputText value="#{beanChild.name}"/> <f:setPropertyActionListener target="#{managedBeanCatalogBrowse.categoryId}" value="#{beanChild.categoryId}" /> </h:commandLink> </h:column> </t:dataTable> </h4> </blockquote> </h:form>4. Define the ManagedBean for the JSP In this example, the list is generated in the methods addCategoryToPath.
import org.apache.myfaces.custom.datalist.HtmlDataList; import org.apache.myfaces.component.html.ext.HtmlDataTable; . . . // category children support private List categoryChildrenList = null; private HtmlDataTable categoryChildrenTable; private String categoryChildId = null; . . . public String actionAddCategorytoPath() { // get admin user's role String roleAdmin = (String) session.getAttribute("role"); // instantiate models ModelCategoryAdmin modelCategoryAdmin = new ModelCategoryAdmin(); // reset lists support resetProductList(); resetProductExpandList(); BeanCategory dataBeanFind = new BeanCategory(); dataBeanFind.setCategoryId( categoryId ); BeanCategory dataBeanNew = modelCategoryAdmin.find( dataBeanFind, roleAdmin ); // test failure if ( ! dataBeanNew.isOk() ) { return "browseCatalogAgain"; } // rebuild category collectionBean and links string CollectionBean collectionBeanCategoryPathLinks = (CollectionBean) session.getAttribute( "collectionBeanCategoryPathLinks" ); collectionBeanCategoryPathLinks.add( dataBeanNew ); //String categoryPathLinks = Util.getCategoryPathLinksString(collectionBeanCategoryPathLinks); session.setAttribute( "collectionBeanCategoryPathLinks", collectionBeanCategoryPathLinks ); //session.setAttribute( "categoryPathLinks", categoryPathLinks ); // clear categoryChildrenList and productList categoryChildrenList.clear(); if ( ! (productList == null) ) productList.clear(); return "browseCatalogAgain"; }Building more complex tables, such as those with multiple columns, will require additional tags or tag attributes. See, especially, <h:panelGrid>, <h:column>, and <f:facet>.5. Define the JSP for a dynamic expanding table with multiple columns and URLs; in this example, the table is supported by the product support clause in 2, above:
<h:form id="browseProductsForm"> <blockquote> <t:dataTable id="productTable" value="#{managedBeanCatalogBrowse.productList}" var="beanProduct" binding="#{managedBeanCatalogBrowse.productTable}" renderedIfEmpty="false" > <h:column> <f:facet name="header"> <h3><h:outputText value="Browse Products" /></h3> </f:facet> <h:panelGrid columns="2" width="60%" > <!-- left column --> <h:panelGrid columns="1" width="150" > <t:graphicImage url="#{beanProduct.imageFileSmallUrl}" /> </h:panelGrid> <!-- right column --> <h:panelGrid columns="1" width="300" columnClasses="COLUMNLABEL" > <h:outputLabel value="#{beanProduct.name}" /> <h:outputText value="#{beanProduct.descriptionShort}"/> <h:outputText value="Price: #{beanProduct.priceAsString}"/> <h:outputText value="Available: #{beanProduct.availableAsString}"/> <h:commandLink action="#{managedBeanCatalogBrowse.actionExpandProduct}" > <h:outputText value="See Product Details"/> <f:setPropertyActionListener target="#{managedBeanCatalogBrowse.productId}" value="#{beanProduct.productId}" /> </h:commandLink> </h:panelGrid> </h:panelGrid> <!-- separator --> <h:panelGrid columns="1" width="450"> <hr/> </h:panelGrid> </h:column> </t:dataTable> </blockquote> </h:form>6. Define the ManagedBean for the JSP to display expanded product information. In this example, the list is generated in the methods actionExpandProduct
public String actionExpandProduct() { // product expand support private List productExpandList = null; private HtmlDataTable productExpandTable; private String quantityAsString = "1"; . . . // get admin user's role String roleAdmin = (String) session.getAttribute("role"); // instantiate models ModelProductAdmin modelProductAdmin = new ModelProductAdmin(); // get the full product info BeanProduct dataBeanFind = new BeanProduct(); dataBeanFind.setProductId( productId ); BeanProduct dataBeanNew = modelProductAdmin.find( dataBeanFind, roleAdmin ); // test failure if ( ! dataBeanNew.isOk() ) { return "browseCatalogAgain"; } else { CollectionBean collectionBeanProductExpand = new CollectionBean(); // update product bean int productId = dataBeanNew.getProductId(); String imageType = dataBeanNew.getImageType(); dataBeanNew.setImageFileUrl( Util.getImageUrl(productId, imageType, Constant.IMAGELARGE) ); collectionBeanProductExpand.add( dataBeanNew ); session.setAttribute( "collectionBeanProductExpand", collectionBeanProductExpand ); setProductExpandList( collectionBeanProductExpand.getDataBeans() ); return "browseProductExpand"; } }
7. To display expanded product information, as generated in 6, above, you will most likely need a new JSP. It may include some of the display components shown above, such as category context; the key dynamic table for expanded product information is shown, below.<t:dataTable id="productTable" value="#{managedBeanCatalogBrowse.productExpandList}" var="beanProduct" binding="#{managedBeanCatalogBrowse.productExpandTable}" renderedIfEmpty="false" > <h:column> <h:panelGrid columns="2" width="60%" > <!-- left column --> <h:panelGrid columns="1" width="150" > <t:graphicImage url="#{beanProduct.imageFileUrl}" /> </h:panelGrid> <!-- right column --> <h:panelGrid columns="1" width="300" columnClasses="COLUMNLABEL" > <h:outputText value="#{beanProduct.name}" /> <h:outputText value="#{beanProduct.description}"/> <h:outputText value="Price: #{beanProduct.priceAsString}"/> <h:outputText value="Available: #{beanProduct.availableAsString}"/> <h:panelGrid columns="2" width="300" columnClasses="COLUMNLABEL" > <h:outputText value="Quantity: " /> <h:inputText id="quantityAsString" value="#{managedBeanCatalogBrowse.quantityAsString}" /> </h:panelGrid> <h:commandButton action="#{managedBeanCatalogBrowse.actionAddToCart}" value="Add To Cart" style="background-color: rgb(163, 200, 250)" > <f:setPropertyActionListener target="#{managedBeanCatalogBrowse.productId}" value="#{beanProduct.productId}" /> </h:commandButton> <h:outputText value="#{managedBeanCatalogBrowse.addToCartMessage}" /> <h:commandLink action="#{managedBeanCatalogBrowse.actionContinueShopping}"> <h:outputText value="Continue Shopping"/> </h:commandLink> </h:panelGrid> </h:panelGrid> </h:column> </t:dataTable>