Introduction
I have been working on JSF tables for the various projects I have been involved with over the years. Starting in 2012, I began looking at RichFaces <rich:dataTable /> for some projects at my day job. The research into how to handle a number of complex situations has been enlightening to say the least.The table is the most complex component in HTML. It is seemingly boundless in its extensibility. You can have multi-column headers that span multiple rows, you can multi-row cells, or multi-column cells. Tables can be displayed left-to-right, or right-to-left, top-to-bottom and vice-versa. As a result, when developing components for JSF, or any component framework, decisions must be made on how to generate them.
A couple of the component frameworks like PrimeFaces, and RichFaces allow developers to create more complex tables with more ease. However there are limitations with each of these frameworks. We trade flexibility for consistency, and this is fine in most cases.
The demonstration code in this post is about getting some of the flexibility back, or taking advantage of the flexibility that comes with a framework like RichFaces. We will gain the flexibility back, but it is a function of complexity. The examples will show you techniques for doing the "same thing" in multiple ways. For example, sorting can be done on the server, client, or a combination of both.
The question is where we put the complex bits. The answer to that question depends on you as a developer. You need to examine the problem domain, and understand the limits to the techniques presented.
Solutions
Please let me confess something. I like building HTML objects programmatically. There I said it. In this case I am trading the ease of development for flexibility. The solutions below will demonstrate the different techniques for accomplishing the same functionality. Please examine the code carefully before discounting it. I spent a lot of time playing with it to make it look simple.The code for this project was developed using NetBeans and Apache Maven. The code was tested on GlassFish 3.1.2.2 and 4.0. It should work on other application servers, but I have not tested it on other servers. This project assumes you are using NetBeans which includes a sample database that these examples require. If you are not using NetBeans, you will need to create your own database with sample data to display some of the tables.
The code can be downloaded from Bitbucket at the link below, or in the references section at the end of the post.
richfaces-tables-poc
Dynamic Data Table with Sorting
![]() |
Dynamic Table with Sorting |
@ManagedBean
. The bean is responsible for generating the table programmatically, and returning it back to the page. The data is sortable by column.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <? xml version = '1.0' encoding = 'UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> < h:head > < title >Dynamic Data Table Design #1</ title > </ h:head > < h:body > < h1 > Dynamic Data Table Design #1</ h1 > < p > The table is bound to the page backing bean, and is generated dynamically. Please use the Source and Code links to see the details. </ p > < h:form id = "form1" > < rich:dataTable id = "dataTable" binding = "#{dataTable1.dataTable}" /> </ h:form > < div style = "padding-top: 5px;" > < a href = "#{facesContext.externalContext.requestContextPath}" >Index</ a > < a href = "#{facesContext.externalContext.requestContextPath}/source/dataTable1.xhtml" >Source</ a > < a href = "#{facesContext.externalContext.requestContextPath}/source/resources/src/dataTable1.java" >Code</ a > </ div > </ h:body > </ html > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | package com.bluelotussoftware.example.richfaces; import com.bluelotussoftware.example.richfaces.model.Customer; import com.bluelotussoftware.example.richfaces.ssb.CustomerFacade; import com.bluelotussoftware.jsf.utils.JSFUtils; import java.io.Serializable; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import javax.annotation.PostConstruct; import javax.ejb.EJB; import javax.enterprise.context.SessionScoped; import javax.faces.application.Application; import javax.faces.component.html.HtmlOutputText; import javax.faces.context.FacesContext; import javax.inject.Named; import org.richfaces.component.SortOrder; import org.richfaces.component.UIColumn; import org.richfaces.component.UIColumnGroup; import org.richfaces.component.UICommandLink; import org.richfaces.component.UIDataTable; /** * <p> Proof of Concept #1 Programmatic RichFaces data table * <code><rich:dataTable/></code> with server side sorting</p> * * <p> <strong>Note:</strong> Please note that the scope must be set to session * for the object holding a reference to the bound datatable.</p> * * @author John Yeary * @version 1.0 */ @Named @SessionScoped public class DataTable1 implements Serializable { private static final long serialVersionUID = 3733919546663290317L; private List<customer> customers; private SortOrder nameSortOrder = SortOrder.unsorted; private SortOrder creditSortOrder = SortOrder.unsorted; private SortOrder phoneSortOrder = SortOrder.unsorted; @EJB private CustomerFacade cf; private UIDataTable dataTable; public DataTable1() { customers = new ArrayList<customer>(); } @PostConstruct private void init() { customers.addAll(cf.findAll()); Class<?>[] klazz = new Class<?>[]{}; Application application = FacesContext.getCurrentInstance().getApplication(); // Create RichFaces Table <rich:dataTable/> dataTable = (UIDataTable) application.createComponent(UIDataTable.COMPONENT_TYPE); dataTable.setVar( "customer" ); dataTable.setValue(customers); // Create A4J CommandLink <a4j:commandLink/> Column Headers UICommandLink clink = (UICommandLink) application.createComponent(UICommandLink.COMPONENT_TYPE); clink.setValueExpression( "value" , JSFUtils.createValueExpression( "#{dataTable1.customerColumnHeader}" , String. class )); clink.setActionExpression(JSFUtils.createMethodExpression( "#{dataTable1.nsort()}" , String. class , klazz)); clink.setRender( "dataTable" ); UICommandLink clink1 = (UICommandLink) application.createComponent(UICommandLink.COMPONENT_TYPE); clink1.setValue( "Phone" ); clink1.setActionExpression(JSFUtils.createMethodExpression( "#{dataTable1.psort()}" , String. class , klazz)); clink1.setRender( "dataTable" ); UICommandLink clink2 = (UICommandLink) application.createComponent(UICommandLink.COMPONENT_TYPE); clink2.setValue( "Credit Limit" ); clink2.setActionExpression(JSFUtils.createMethodExpression( "#{dataTable1.csort()}" , String. class , klazz)); clink2.setRender( "dataTable" ); // Create Data Elements HtmlOutputText htmlOutputText = (HtmlOutputText) application.createComponent(HtmlOutputText.COMPONENT_TYPE); htmlOutputText.setValueExpression( "value" , JSFUtils.createValueExpression( "#{customer.name}" , String. class )); HtmlOutputText htmlOutputText1 = (HtmlOutputText) application.createComponent(HtmlOutputText.COMPONENT_TYPE); htmlOutputText1.setValueExpression( "value" , JSFUtils.createValueExpression( "#{customer.phone}" , String. class )); HtmlOutputText htmlOutputText2 = (HtmlOutputText) application.createComponent(HtmlOutputText.COMPONENT_TYPE); htmlOutputText2.setValueExpression( "value" , JSFUtils.createValueExpression( "#{dataTable1.format(customer.creditLimit)}" , String. class )); htmlOutputText2.setValueExpression( "rendered" , JSFUtils.createValueExpression( "#{customer.creditLimit gt 25000}" , Boolean. class )); // Create RichFaces Columns <rich:column/> UIColumn column = (UIColumn) application.createComponent(UIColumn.COMPONENT_TYPE); column.setValueExpression( "sortBy" , JSFUtils.createValueExpression( "#{customer.name}" , String. class )); column.setValueExpression( "sortOrder" , JSFUtils.createValueExpression( "#{dataTable1.nameSortOrder}" , SortOrder. class )); UIColumn column1 = (UIColumn) application.createComponent(UIColumn.COMPONENT_TYPE); column1.setValueExpression( "sortBy" , JSFUtils.createValueExpression( "#{customer.phone}" , String. class )); column1.setValueExpression( "sortOrder" , JSFUtils.createValueExpression( "#{dataTable1.phoneSortOrder}" , SortOrder. class )); column1.setValueExpression( "comparator" , JSFUtils.createValueExpression( "#{dataTable1.phoneComparator}" , Comparator. class )); UIColumn column2 = (UIColumn) application.createComponent(UIColumn.COMPONENT_TYPE); column2.setValueExpression( "sortBy" , JSFUtils.createValueExpression( "#{customer.creditLimit}" , String. class )); column2.setValueExpression( "sortOrder" , JSFUtils.createValueExpression( "#{dataTable1.creditSortOrder}" , SortOrder. class )); column2.setValueExpression( "comparator" , JSFUtils.createValueExpression( "#{dataTable1.creditComparator}" , Comparator. class )); // Assemble Columns and values column.setHeader(clink); column.getChildren().add(htmlOutputText); column1.setHeader(clink1); column1.getChildren().add(htmlOutputText1); column2.setHeader(clink2); column2.getChildren().add(htmlOutputText2); // Create Table Header UIColumn hcolumn = (UIColumn) application.createComponent(UIColumn.COMPONENT_TYPE); hcolumn.setColspan( 3 ); HtmlOutputText columnText = (HtmlOutputText) application.createComponent(HtmlOutputText.COMPONENT_TYPE); columnText.setValue( "Customer Information" ); hcolumn.getChildren().add(columnText); UIColumnGroup columnGroup = (UIColumnGroup) application.createComponent(UIColumnGroup.COMPONENT_TYPE); columnGroup.getChildren().add(hcolumn); // Assemble Table dataTable.setHeader(columnGroup); dataTable.getChildren().add(column); dataTable.getChildren().add(column1); dataTable.getChildren().add(column2); } public UIDataTable getDataTable() { return dataTable; } public void setDataTable(UIDataTable dataTable) { this .dataTable = dataTable; } public List<customer> getCustomers() { return customers; } public SortOrder getNameSortOrder() { return nameSortOrder; } public SortOrder getCreditSortOrder() { return creditSortOrder; } public SortOrder getPhoneSortOrder() { return phoneSortOrder; } /** * Customer name sorting enumeration "three position switch": * default (unsorted), ascending, and descending. */ public void nsort() { creditSortOrder = SortOrder.unsorted; phoneSortOrder = SortOrder.unsorted; switch (nameSortOrder) { case unsorted: { nameSortOrder = SortOrder.ascending; break ; } case ascending: { nameSortOrder = SortOrder.descending; break ; } case descending: { nameSortOrder = SortOrder.unsorted; break ; } } } /** * Credit limit sorting enumeration "three position switch": * default (unsorted), ascending, and descending. */ public void csort() { nameSortOrder = SortOrder.unsorted; phoneSortOrder = SortOrder.unsorted; switch (creditSortOrder) { case unsorted: { creditSortOrder = SortOrder.ascending; break ; } case ascending: { creditSortOrder = SortOrder.descending; break ; } case descending: { creditSortOrder = SortOrder.unsorted; break ; } } } /** * Phone sorting enumeration "three position switch": default * (unsorted), ascending, and descending. */ public void psort() { nameSortOrder = SortOrder.unsorted; creditSortOrder = SortOrder.unsorted; switch (phoneSortOrder) { case unsorted: { phoneSortOrder = SortOrder.ascending; break ; } case ascending: { phoneSortOrder = SortOrder.descending; break ; } case descending: { phoneSortOrder = SortOrder.unsorted; break ; } } } public Comparator<customer> getPhoneComparator() { return new Comparator<customer>() { @Override public int compare(Customer o1, Customer o2) { return o1.getPhone().compareTo(o2.getPhone()); } }; } public Comparator<customer> getCreditComparator() { return new Comparator<customer>() { @Override public int compare(Customer o1, Customer o2) { return o1.getCreditLimit().compareTo(o2.getCreditLimit()); } }; } /** * This method returns the customer name header with the specified sort * order based on the current {@link SortOrder}. * * @return customer name header with the specified sort order. */ public String getCustomerColumnHeader() { switch (nameSortOrder) { case unsorted: { return "Customer Name" ; } default : { return "Customer Name (" + nameSortOrder + ")" ; } } } /** * Generates custom formatted USD currency value based on {@code Integer}. * * @param value The value to be formatted. * @return $USD formatted value. */ public String format(Integer value) { return String.format( "$ %1$,d" , value); } } |
@ManagedBean
. If you are satisfied with this technique, lets take a look at another one.
Dynamic Data Table with Sorting Revisited
![]() |
Dynamic Table |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <? xml version = '1.0' encoding = 'UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> < h:head > < title >Dynamic Data Table Design #2</ title > </ h:head > < h:body > < h1 > Dynamic Data Table Design Design #2</ h1 > < p > The table is bound to the page backing bean, and is generated dynamically. Please use the Source and Code links to see the details. </ p > < h:form id = "form1" > < rich:dataTable id = "dataTable" binding = "#{dataTable2.dataTable}" /> </ h:form > < div style = "padding-top: 5px;" > < a href = "#{facesContext.externalContext.requestContextPath}" >Index</ a > < a href = "#{facesContext.externalContext.requestContextPath}/source/dataTable2.xhtml" >Source</ a > < a href = "#{facesContext.externalContext.requestContextPath}/source/resources/src/dataTable2.java" >Code</ a > </ div > </ h:body > </ html > |
The more simplified code in the
@ManagedBean
is shown below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | package com.bluelotussoftware.example.richfaces; import com.bluelotussoftware.jsf.utils.JSFUtils; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.annotation.PostConstruct; import javax.enterprise.context.SessionScoped; import javax.faces.application.Application; import javax.faces.component.html.HtmlOutputText; import javax.faces.context.FacesContext; import javax.inject.Named; import org.richfaces.component.SortOrder; import org.richfaces.component.UIColumn; import org.richfaces.component.UICommandLink; import org.richfaces.component.UIDataTable; /** * <p> Proof of Concept #2 Programmatic RichFaces data table * <code><rich:dataTable/></code> with server side sorting</p> * * <p> <strong>Note:</strong> Please note that the scope must be set to session * for the object holding a reference to the bound datatable.</p> * * @author John Yeary * @version 1.0 */ @Named @SessionScoped public class DataTable2 implements Serializable { private static final long serialVersionUID = -2771295649562837525L; private SortOrder sorting = SortOrder.unsorted; private static final String DATA_TABLE_NAME = "dataTable" ; private UIDataTable dataTable; public DataTable2() { } @PostConstruct private void init() { FacesContext context = FacesContext.getCurrentInstance(); Application application = context.getApplication(); // ~~~~~~~~~~~~~~~~~~~~ Data Table dataTable = (UIDataTable) application.createComponent(UIDataTable.COMPONENT_TYPE); dataTable.setVar( "v" ); dataTable.setValue(getData()); UIColumn column0 = createUIColumn(context, "#{v.get(0).value}" , String. class , "#{dataTable2.sorting}" ); UIColumn column1 = createUIColumn(context, "#{v.get(1).value}" , String. class , "#{dataTable2.sorting}" ); UICommandLink commandLink0 = createUICommandLink(context, "Column 0" , DATA_TABLE_NAME, "#{dataTable2.sort()}" ); UICommandLink commandLink1 = createUICommandLink(context, "Column 1" , DATA_TABLE_NAME, "#{dataTable2.sort()}" ); HtmlOutputText htmlOutputText0 = createHtmlOutputText(context, "#{v.get(0).value}" , String. class ); HtmlOutputText htmlOutputText1 = createHtmlOutputText(context, "#{v.get(1).value}" , String. class ); column0.setHeader(commandLink0); column0.getChildren().add(htmlOutputText0); column1.setHeader(commandLink1); column1.getChildren().add(htmlOutputText1); dataTable.getChildren().add(column0); dataTable.getChildren().add(column1); } public SortOrder getSorting() { return sorting; } public void setSorting(SortOrder sorting) { this .sorting = sorting; } public UIDataTable getDataTable() { return dataTable; } public void setDataTable(UIDataTable dataTable) { this .dataTable = dataTable; } public void sort() { switch (sorting) { case unsorted: { sorting = SortOrder.ascending; break ; } case ascending: { sorting = SortOrder.descending; break ; } case descending: { sorting = SortOrder.unsorted; break ; } } } public UICommandLink createUICommandLink( final FacesContext context, final String value, final String render, final String methodExpression) { Class<?>[] clazz = new Class<?>[]{}; UICommandLink link = (UICommandLink) context.getApplication().createComponent(UICommandLink.COMPONENT_TYPE); link.setValue(value); link.setRender(render); link.setActionExpression(JSFUtils.createMethodExpression(methodExpression, String. class , clazz)); return link; } public UIColumn createUIColumn( final FacesContext context, final String sortByValueExpression, final Class<?> sortByType, final String sortOrderValueExpression) { UIColumn column = (UIColumn) context.getApplication().createComponent(UIColumn.COMPONENT_TYPE); column.setValueExpression( "sortBy" , JSFUtils.createValueExpression(sortByValueExpression, sortByType)); column.setValueExpression( "sortOrder" , JSFUtils.createValueExpression(sortOrderValueExpression, SortOrder. class )); return column; } public HtmlOutputText createHtmlOutputText( final FacesContext context, final String valueValueExpression, Class<?> valueType) { HtmlOutputText text = (HtmlOutputText) context.getApplication().createComponent(HtmlOutputText.COMPONENT_TYPE); text.setValueExpression( "value" , JSFUtils.createValueExpression(valueValueExpression, valueType)); return text; } public List<List<valueholder>> getData() { List<List<valueholder>> datax = new ArrayList<List<valueholder>>(); for ( int i = 0 ; i < 10 ; i++) { List<ValueHolder> subelement = new ArrayList<valueholder>(); for ( int j = 0 ; j < 10 ; j++) { ValueHolder vh = new ValueHolder(String.format( "Row %1$d Element %2$d" , i, j)); List<ValueHolder> sub = new ArrayList<valueholder>(); for ( int k = 0 ; k < 3 ; k++) { ValueHolder sube = new ValueHolder( "SubElement " + k); List<ValueHolder> subsub = new ArrayList<valueholder>(); for ( int l = 0 ; l < 10 ; l++) { ValueHolder subx = new ValueHolder( "SubSubElement " + l); subsub.add(subx); } sube.setSubValues(subsub); sub.add(sube); } vh.setSubValues(sub); subelement.add(vh); } datax.add(subelement); } Collections.shuffle(datax); return datax; } } |
The code above was written before I added more functionality to my jsf-utils project. The new methods would shorten this considerably, but it would still be fairly complex.
Dynamic Table using JSP/JSTL Tags with JSF
![]() |
JSF/JSTL Dynamic Table |
In this example, I will generate the rows and columns using
<c:forEach />
. This transfers a lot of the complexity to the page and away from the @ManagedBean
. Since we are using <c:forEach />
, our mechanism for sorting has to change. I used Query jquery.tablesorter.js to allow sorting of the headers.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | <? xml version = '1.0' encoding = 'UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" < h:head > < title >Dynamic Data Table Design #3</ title > </ h:head > < h:body > < h1 > Dynamic Data Table Design Design #3</ h1 > < p > The table is bound to the page backing bean, and is generated dynamically using < code >< c:forEach /></ code > to create the column elements. This technique is not recommended unless you understand the limitations of using JSP/JSTL tags with JSF. This is a good working example of the technique. This table also uses jQuery < i >jquery.tablesorter.js</ i > to allow sorting of the headers. Click on the headers to sort. </ p > < p > Please use the Source and Code links to see the details. </ p > < h:form id = "form1" > < rich:dataTable id = "dataTable" value = "#{dataTable3.customers}" var = "customer" rowKeyVar = "idx" styleClass = "tablesorter" > < c:forEach items = "#{dataTable3.customerByIndex(idx)}" var = "cx" > < f:facet name = "header" > < rich:columnGroup > < rich:column colspan = "2" > < h:outputText value = "Customers" /> </ rich:column > < rich:column breakRowBefore = "true" > < h:outputText value = "Name" /> </ rich:column > < rich:column > < h:outputText value = "Phone" /> </ rich:column > </ rich:columnGroup > </ f:facet > < rich:column > < h:outputText value = "#{cx.name}" /> < f:facet name = "footer" > Number of Customers: #{dataTable3.customers.size()} </ f:facet > </ rich:column > < rich:column > < h:outputText value = "#{cx.phone}" /> < f:facet name = "footer" /> </ rich:column > </ c:forEach > </ rich:dataTable > < rich:jQuery /> < h:outputScript name = "jquery.tablesorter.js" library = "js" /> </ h:form > < div style = "padding-top: 5px;" > < a href = "#{facesContext.externalContext.requestContextPath}" >Index</ a > < a href = "#{facesContext.externalContext.requestContextPath}/source/dataTable3.xhtml" >Source</ a > < a href = "#{facesContext.externalContext.requestContextPath}/source/resources/src/dataTable3.java" >Code</ a > </ div > < script type = "text/javascript" > $(document).ready(function() { $('#form1\\:dataTable').tablesorter(); }); </ script > </ h:body > </ html > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | package com.bluelotussoftware.example.richfaces; import com.bluelotussoftware.example.richfaces.model.Customer; import com.bluelotussoftware.example.richfaces.ssb.CustomerFacade; import java.util.ArrayList; import java.util.List; import javax.annotation.PostConstruct; import javax.ejb.EJB; import javax.enterprise.context.RequestScoped; import javax.inject.Named; /** * Proof of Concept #3 Client Side Sorting using jQuery TableSorter 2.0 * * @author John Yeary * @version 1.0 */ @Named @RequestScoped public class DataTable3 { private static final long serialVersionUID = -1246509549850361939L; private List<customer> customers; @EJB private CustomerFacade customerFacade; public DataTable3() { customers = new ArrayList<customer>(); } @PostConstruct private void init() { customers.addAll(customerFacade.findAll()); } public List<customer> getCustomers() { return customers; } /** * This method is used by * <code><c:forEach/></code> * <code>items</code> attribute which requires a {@code Collection}, or an * array to iterate over; * * @param index the {@link Customer} at the index position in the customer * list. * @return a list containing a single customer at the specified index. */ public List<customer> customerByIndex( final int index) { List<customer> customer = new ArrayList<customer>(); customer.add(customers.get(index)); return customer; } } |
Complex Data Table Design
![]() |
Complex Table Design |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | <? xml version = '1.0' encoding = 'UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> < h:head > < title >Complex Data Table Design</ title > </ h:head > < h:body > < h:form id = "form1" > < h1 > Complex Data Table Design</ h1 > < p > This example demonstrates how to use the < code >< rich:columnGroup /></ code > tag, along with Expression Language (EL) formatting of column output. It also demonstrates how to use AJAX sorting of the customer name. </ p > < p > Please use the Source and Code links to see the details. </ p > < rich:dataTable id = "dataTable" value = "#{complexDataTable.customers}" var = "customer" > < f:facet name = "header" > < rich:columnGroup > < rich:column colspan = "6" > < h:outputText value = "Customers" /> </ rich:column > < rich:column breakRowBefore = "#{true}" rowspan = "2" colspan = "2" /> < rich:column colspan = "2" > < h:outputText value = "Address" /> </ rich:column > < rich:column > < h:outputText value = "Contact Information" /> </ rich:column > < rich:column rowspan = "2" > < h:outputText value = "Credit Limit" /> </ rich:column > < rich:column breakRowBefore = "#{true}" > < h:outputText value = "City" /> </ rich:column > < rich:column > < h:outputText value = "State" /> </ rich:column > < rich:column > < h:outputText value = "Phone" /> </ rich:column > </ rich:columnGroup > </ f:facet > < rich:column > < f:facet name = "header" > < h:outputText value = "Sales Code Word" /> </ f:facet > < h:outputText rendered="#{customer.creditLimit eq 50000 || customer.creditLimit eq 70000 || customer.creditLimit eq 90000}" value = "Partner" /> < h:outputText rendered = "#{customer.creditLimit eq 5000000}" value = "Head Kahuna" /> < h:outputText rendered = "#{customer.creditLimit eq 100000}" value = "Big Tuna" /> </ rich:column > < rich:column sortBy = "#{customer.name}" sortOrder = "#{complexDataTable.sorting}" > < f:facet name = "header" > < a4j:commandLink render = "dataTable" value = "#{complexDataTable.customerColumnHeader}" action = "#{complexDataTable.sort()}" /> </ f:facet > < h:outputText value = "#{customer.name}" /> </ rich:column > < rich:column > < h:outputText value = "#{customer.city}" /> </ rich:column > < rich:column > < h:outputText value = "#{customer.state}" /> </ rich:column > < rich:column > < h:outputText value = "#{customer.phone}" /> </ rich:column > < rich:column > < h:outputText value = "#{complexDataTable.format(customer.creditLimit)}" /> </ rich:column > </ rich:dataTable > </ h:form > < div style = "padding-top: 5px;" > < a href = "#{facesContext.externalContext.requestContextPath}" >Index</ a > < a href = "#{facesContext.externalContext.requestContextPath}/source/complexLayout.xhtml" >Source</ a > < a href = "#{facesContext.externalContext.requestContextPath}/source/resources/src/complexDataTable.java" >Code</ a > </ div > </ h:body > </ html > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | package com.bluelotussoftware.example.richfaces; import com.bluelotussoftware.example.richfaces.model.Customer; import com.bluelotussoftware.example.richfaces.ssb.CustomerFacade; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.annotation.PostConstruct; import javax.ejb.EJB; import javax.enterprise.context.SessionScoped; import javax.inject.Named; import org.richfaces.component.SortOrder; /** * Proof of Concept #4 Complex layout table with server side sorting on single * column. * * @author John Yeary * @version 1.0 */ @Named @SessionScoped public class ComplexDataTable implements Serializable { private static final long serialVersionUID = -5343878110987753773L; private List<customer> customers; @EJB private CustomerFacade customerFacade; private SortOrder sorting = SortOrder.unsorted; public ComplexDataTable() { customers = new ArrayList<customer>(); } @PostConstruct private void init() { customers.addAll(customerFacade.findAll()); } public List<customer> getCustomers() { return Collections.unmodifiableList(customers); } public SortOrder getSorting() { return sorting; } /** * Sorting enumeration "three position switch": default * (unsorted), ascending, and descending. */ public void sort() { switch (sorting) { case unsorted: { sorting = SortOrder.ascending; break ; } case ascending: { sorting = SortOrder.descending; break ; } case descending: { sorting = SortOrder.unsorted; break ; } } } /** * This method returns the customer name header with the specified sort * order based on the current {@link SortOrder}. * * @return customer name header with the specified sort order. */ public String getCustomerColumnHeader() { switch (sorting) { case unsorted: { return "Customer Name" ; } default : { return "Customer Name (" + sorting + ")" ; } } } /** * Generates custom formatted USD currency value based on {@code Integer}. * * @param value The value to be formatted. * @return $USD formatted value. */ public String format(Integer value) { return String.format( "$ %1$,d" , value); } } |
0 comments :
Post a Comment