-
1. Re: rich:datatable rowspan using rich:subtable
deadlock_gr Apr 22, 2010 8:01 AM (in response to deadlock_gr)Anyone?
By the way, I saw that IceFaces has a "grouping" feature in their datatable. So, they achieve rowspanning by setting fields by which the rows are "grouped". So, in my example, if I set the company fields to be group fields I could get the rowspan I want, because the content is the same for companies.
In Richfaces I believe that the subtable is a better option. But I have not managed to make also company rows with no products appear. Has anyone managed this?
-
2. Re: rich:datatable rowspan using rich:subtable
deadlock_gr Apr 27, 2010 5:15 AM (in response to deadlock_gr)Please note that I have also a third level of hierarchy. So, the Products break down into another list.
-
3. Re: rich:datatable rowspan using rich:subtable
ilya_shaikovsky Apr 27, 2010 7:25 AM (in response to deadlock_gr)At first want to say sorry for such a long delay. And thanks for your efforts and patience.
You provided really cool workaround for very old issue https://jira.jboss.org/jira/browse/RF-1870. And your last question looks not difficult to solve. I recreated richfaces-demo sample using your code instead of using column for master table. And yes.. if the subtable has no data - it's not rendered. But just for this case we could add column to master table conditionally.
look to my sources and pay attention to panelGroup after the subtable. (the output itself has some problem with spaning but just wanted to share my idea and think you'll add proper spans in your code)
<rich:dataTable onRowMouseOver="this.style.backgroundColor='#F1F1F1'" onRowMouseOut="this.style.backgroundColor='#{a4jSkin.tableBackgroundColor}'" cellpadding="0" cellspacing="0" width="700" border="0" var="record" value="#{report.expReport.records}"> <f:facet name="header"> <rich:columnGroup> ///header content </rich:columnGroup> </f:facet> <rich:subTable onRowMouseOver="this.style.backgroundColor='#F8F8F8'" onRowMouseOut="this.style.backgroundColor='#{a4jSkin.tableBackgroundColor}'" var="expense" value="#{record.items}" rowKeyVar="rowKey"> <rich:column rowspan="#{record.items.size()}" rendered="#{rowKey eq 0}"> #{record.city} </rich:column> <rich:column> <h:outputText value="#{expense.day}"></h:outputText> <f:facet name="footer"> <rich:spacer /> </f:facet> </rich:column> <rich:column> <h:outputText value="#{expense.meals}"><f:convertNumber pattern="$####.00" /></h:outputText> <f:facet name="footer"> <h:outputText value="#{record.totalMeals}"><f:convertNumber pattern="$####.00" /></h:outputText> </f:facet> </rich:column> <rich:column> <h:outputText value="#{expense.hotels}"><f:convertNumber pattern="$####.00" /></h:outputText> <f:facet name="footer"> <h:outputText value="#{record.totalHotels}"><f:convertNumber pattern="$####.00" /></h:outputText> </f:facet> </rich:column> <rich:column> <h:outputText value="#{expense.transport}"><f:convertNumber pattern="$####.00" /></h:outputText> <f:facet name="footer"> <h:outputText value="#{record.totalTransport}"><f:convertNumber pattern="$####.00" /></h:outputText> </f:facet> </rich:column> <rich:column> <rich:spacer></rich:spacer> <f:facet name="footer"> <h:outputText value="#{record.total}"><f:convertNumber pattern="$####.00" /></h:outputText> </f:facet> </rich:column> </rich:subTable> <rich:columnGroup rendered="#{empty record.items}"> <rich:column>#{record.city}</rich:column> </rich:columnGroup> <f:facet name="footer"> //footer content </f:facet> </rich:dataTable>
-
4. Re: rich:datatable rowspan using rich:subtable
deadlock_gr Apr 27, 2010 7:57 AM (in response to ilya_shaikovsky)Thanks Ilya, will try out ASAP.
But for the snippet I provided, credit must go to Damo from StackOverflow:
http://stackoverflow.com/questions/2028958/richdatatable-rowspan-issue
-
5. Re: rich:datatable rowspan using rich:subtable
deadlock_gr Apr 27, 2010 1:47 PM (in response to deadlock_gr)Unfortunately, I have a problem with the third level of data. I have the following hierarchy:
Product > Application > Version
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html 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:c="http://java.sun.com/jstl/core" xmlns:rich="http://richfaces.org/rich" xmlns:fn="http://java.sun.com/jsp/jstl/functions"> <ui:composition template="/WEB-INF/facelets/templates/template.xhtml"> <ui:define name="content"> <h:form prependId="false"> <h:commandButton action="Back" value="#{msgs.btn_back_to_home_page}" /> <p>#{msgs.title_products_procedures_submissions}</p> <rich:dataTable id="prodProcSubTable" value="#{prodProcSubListDataModel}" var="prod" styleClass="expandWidth"> <f:facet name="header"> <rich:columnGroup> <rich:column breakBefore="true" styleClass="prodProcSubList_column1"> <h:outputText styleClass="headerText" value="Product" /> </rich:column> <rich:column styleClass="prodProcSubList_column2"> <h:outputText styleClass="headerText" value="Applicant Id (2-digit)" /> </rich:column> <rich:column styleClass="prodProcSubList_column2"> <h:outputText styleClass="headerText" value="PI Version Id (5-digit)" /> </rich:column> </rich:columnGroup> </f:facet> <rich:subTable value="#{prod.applications}" var="app" styleClass="expandWidth" rowKeyVar="appKey"> <rich:column rowspan="#{rowspan.calcProductRowspan(prod)}" rendered="#{appKey eq 0}"> #{prod.inventedName} </rich:column> <rich:subTable value="#{app.applicationPiversions}" var="appPiVer" styleClass="expandWidth" columnClasses="prodProcSubList_column" rowKeyVar="appPiVerKeyVar"> <rich:column rowspan="#{rowspan.calcApplicationRowspan(app)}" rendered="#{appPiVerKeyVar eq 0}"> #{appPiVer.applicationId} </rich:column> <rich:column styleClass="prodProcSubList_column2">#{appPiVer.piVersionId}</rich:column> </rich:subTable> <rich:columnGroup rendered="#{empty app.applicationPiversions}"> <rich:column> #{app.applicationId} </rich:column> <rich:column> NO PI VERSIONS </rich:column> </rich:columnGroup> </rich:subTable> <rich:columnGroup rendered="#{empty prod.applications}"> <rich:column> #{prod.inventedName} </rich:column> <rich:column> NO APPLICATIONS </rich:column> <rich:column> NO PI VERSIONS </rich:column> </rich:columnGroup> </rich:dataTable> </h:form> </ui:define> </ui:composition> </html>
Although the case where no applications (2nd level) exist for a product (1st level) works OK with the columnGroup outside the subtables, I cannot find how to do a similar thing for the case of no Versions (3rd level) for an application (2nd level).
Look what I get by the following code (notice that the 2-digit Application codes appear in the product column, and the NO PI VERSIONS tag appears in the Application column):
Note that I resolved the issue of calculating the rowspan for products (1st level) and applications (2nd level) with a Seam component. There was need for some logic, to calculate that, for example, the rowspan for the following product:
Product
> Application 1
>>>Version 1
>>>Version 2
> Application 2
> Application 3
>>>Version 1
>>>Version 2
is 7. So, I included this logic in the back end.
So, the question is, how do I handle the case where an application (2nd level) does not have any versions (3rd level)?
-
6. Re: rich:datatable rowspan using rich:subtable
ilya_shaikovsky Apr 30, 2010 7:35 AM (in response to deadlock_gr)so as I see you could output columngroup at third level if no data in subtable but the problem in alligning spanning? Or missing something? anyway please attach war sample with java sources for more close investigation..
-
7. Re: rich:datatable rowspan using rich:subtable
deadlock_gr May 3, 2010 3:24 AM (in response to ilya_shaikovsky)Dear Ilya,
I have created a Google Code project (see http://code.google.com/p/richfaces-rowspan/downloads/list), where I show the problem described above. The project is a Maven project, it uses Richfaces and JBoss Seam, and I tested it on JBoss 4.2.3.GA.
The war is also downloadable (from http://richfaces-rowspan.googlecode.com/files/rowspan.war).
As you can see, the page is simple. There is a rich:datatable, which takes a List<Company> and shows it.
- The first Company has 2 Products and each Product has 2 Versions.
- The second Company has 2 Products. The first Product has 2 Versions. The second Product has no versions.
- The third Company has no Products.
After the rich:datatable I I have written by hand a <table> showing the desired output. So, the question is what the rich:datatable has to be in order to display the same as the hardcoded HTML table.
Note: I have also a utility to compute the rowspan for a Company and a Product. Having to use such a utility is a disadvantage. So, if there is a way to avoid it would be desirable.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html 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:c="http://java.sun.com/jstl/core" xmlns:rich="http://richfaces.org/rich" xmlns:fn="http://java.sun.com/jsp/jstl/functions"> <body> <h:form prependId="false"> <rich:dataTable value="#{actionBean.companies}" var="comp"> <f:facet name="header"> <rich:columnGroup> <rich:column breakBefore="true"> <h:outputText value="Company" /> </rich:column> <rich:column> <h:outputText styleClass="headerText" value="Product" /> </rich:column> <rich:column> <h:outputText styleClass="headerText" value="Version)" /> </rich:column> </rich:columnGroup> </f:facet> <rich:subTable value="#{comp.products}" var="prod" rowKeyVar="prodKeyVar"> <rich:column rowspan="#{rowspan.calcCompanyRowspan(comp)}" rendered="#{prodKeyVar eq 0}"> #{comp.name} </rich:column> <rich:subTable value="#{prod.versions}" var="ver" rowKeyVar="verKeyVar"> <rich:column rowspan="#{rowspan.calcProductRowspan(prod)}" rendered="#{verKeyVar eq 0}"> #{prod.name} </rich:column> <rich:column>#{ver.name}</rich:column> </rich:subTable> <rich:columnGroup rendered="#{empty prod.versions}"> <rich:column> #{prod.name} </rich:column> <rich:column> NO VERSIONS </rich:column> </rich:columnGroup> </rich:subTable> <rich:columnGroup rendered="#{empty comp.products}"> <rich:column> #{comp.name} </rich:column> <rich:column> NO PRODUCTS </rich:column> <rich:column> NO VERSIONS </rich:column> </rich:columnGroup> </rich:dataTable> <p>Desired output:</p> <table border="true"> <tbody> <tr> <td rowspan="4">Company A</td> <td rowspan="2">Product A0</td> <td>Version A0</td> </tr> <tr> <td>Version A1</td> </tr> <tr> <td rowspan="2">Product A1</td> <td>Version A3</td> </tr> <tr> <td>Version A4</td> </tr> <tr> <td rowspan="3">Company B</td> <td rowspan="2">Product B0</td> <td>Version B0</td> </tr> <tr> <td>Version B1</td> </tr> <tr> <td>Product B1</td> <td>NO VERSIONS</td> </tr> <tr> <td>Company C</td> <td>NO PRODUCTS</td> <td>NO VERSIONS</td> </tr> </tbody> </table> </h:form> </body> </html>
And the action bean is this:
package org.markos.action; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Begin; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.markos.model.Company; import org.markos.model.Product; import org.markos.model.Version; /** * TODO Place information about the class or interface here * * @author fragkakm */ @Name("actionBean") @Scope(ScopeType.SESSION) public class ActionBean implements Serializable { private List<Company> companies = new ArrayList<Company>(); @Begin public void init() { companies = new ArrayList<Company>(); // add a company with products and with versions Company companyA = new Company(); companyA.setName("Company A"); for (int k = 0; k < 2; k++) { Product prod = new Product(); prod.setName("Product A" + k); for (int m = 0; m < 2; m++) { Version version = new Version(); version.setName("Version A" + m); prod.getVersions().add(version); } companyA.getProducts().add(prod); } // add a company with 2 products, second product has no versions Company companyB = new Company(); companyB.setName("Company B"); Product prodB0 = new Product(); prodB0.setName("Product B0"); for (int n = 0; n < 2; n++) { Version version = new Version(); version.setName("Version B" + n); prodB0.getVersions().add(version); } companyB.getProducts().add(prodB0); Product prodB1 = new Product(); prodB1.setName("Product B1"); // add a company with no products Company companyC = new Company(); companyC.setName("Company C"); companies.add(companyA); companies.add(companyB); companies.add(companyC); System.out.println(companies.size()); } /** * @return the companies */ public List<Company> getCompanies() { init(); return companies; } /** * @param companies * the companies to set */ public void setCompanies(List<Company> companies) { this.companies = companies; } }
-
8. Re: rich:datatable rowspan using rich:subtable
deadlock_gr May 5, 2010 4:05 AM (in response to deadlock_gr)Ping!
-
9. Re: rich:datatable rowspan using rich:subtable
ilya_shaikovsky May 6, 2010 5:26 AM (in response to deadlock_gr)at first the product without versions which is prodB1 in your code - not appears shown just because you just not added it to any company see code
Product prodB1 = new Product(); prodB1.setName("Product B1");
And that's all code that related to B1.
so just add
companyB.getProducts().add(prodB1);
and you also seems should re-check the code which realted to rowspans calculation because products shifted and appears below the company if more than one present and all have more than one version.
-
10. Re: rich:datatable rowspan using rich:subtable
deadlock_gr May 7, 2010 4:22 AM (in response to ilya_shaikovsky)Dear Ilya,
I corrected the datamodel (although this should not have prevented it from rendering correctly).
The rowspanning logic is correct, I checked the printouts.
The problem that I found is that empty <tr></tr> are rendered when I have a rich:column or rich:columnGroup whose rendered attribute evaluates to false. So, although the logic that computes the rowspans is correct, it does not take into account the empty rows, which mess up the rendering.You can find the code that is generated from the richdatatable below, and it renders like this:
When I remove from FireBug the empty rows, this is how it renders (notice reference rendering below). This is exactly what I want.
The current page (committed in Google Code project):
<rich:dataTable value="#{actionBean.companies}" var="comp" first="0" rows="#{rowspan.calcTotalRows(actionBean.companies)}"> <f:facet name="header"> <rich:columnGroup> <rich:column breakBefore="true"> <h:outputText value="Company" /> </rich:column> <rich:column> <h:outputText styleClass="headerText" value="Product" /> </rich:column> <rich:column> <h:outputText styleClass="headerText" value="Version)" /> </rich:column> </rich:columnGroup> </f:facet> <rich:subTable value="#{comp.products}" var="prod" rowKeyVar="prodKeyVar"> <rich:subTable value="#{prod.versions}" var="ver" rowKeyVar="verKeyVar"> <rich:column rowspan="#{rowspan.calcCompanyRowspan(comp)}" rendered="#{(prodKeyVar eq 0) and (verKeyVar eq 0)}"> #{comp.name} </rich:column> <rich:column rowspan="#{rowspan.calcProductRowspan(prod)}" rendered="#{verKeyVar eq 0}"> #{prod.name} </rich:column> <rich:column>#{ver.name}</rich:column> </rich:subTable> <rich:columnGroup rendered="#{empty prod.versions}"> <rich:column rowspan="#{rowspan.calcCompanyRowspan(comp)}" rendered="#{prodKeyVar eq 0}" style="color: green"> #{comp.name} </rich:column> <rich:column> #{prod.name} </rich:column> <rich:column> NO VERSIONS </rich:column> </rich:columnGroup> </rich:subTable> <rich:columnGroup rendered="#{empty comp.products}"> <rich:column> #{comp.name} </rich:column> <rich:column rendered="#{empty comp.products}"> NO PRODUCTS </rich:column> <rich:column rendered="#{empty comp.products}"> NO VERSIONS </rich:column> </rich:columnGroup> </rich:dataTable>
The generated code:
<table id="j_id3" border="0" cellpadding="0" cellspacing="0"> <colgroup span="3"></colgroup> <thead> <tr> <th id="j_id3:j_id5">Company</th> <th id="j_id3:j_id7"><span class="headerText">Product</span></th> <th id="j_id3:j_id9"><span class="headerText">Version)</span></th> </tr> </thead> <tbody id="j_id3:tb"> <tr> <td id="j_id3:0:j_id11:0:j_id12:0:j_id13" rowspan="4">Company A</td> <td id="j_id3:0:j_id11:0:j_id12:0:j_id15" rowspan="2">Product A0</td> <td id="j_id3:0:j_id11:0:j_id12:0:j_id17">Version A0</td> </tr> <tr> <td id="j_id3:0:j_id11:0:j_id12:1:j_id17">Version A1</td> </tr> <tr></tr> <tr> <td id="j_id3:0:j_id11:1:j_id12:0:j_id15" rowspan="2">Product A1</td> <td id="j_id3:0:j_id11:1:j_id12:0:j_id17">Version A0</td> </tr> <tr> <td id="j_id3:0:j_id11:1:j_id12:1:j_id17">Version A1</td> </tr> <tr></tr> <tr></tr> <tr> <td id="j_id3:1:j_id11:0:j_id12:0:j_id13" rowspan="3">Company B</td> <td id="j_id3:1:j_id11:0:j_id12:0:j_id15" rowspan="2">Product B0</td> <td id="j_id3:1:j_id11:0:j_id12:0:j_id17">Version B0</td> </tr> <tr> <td id="j_id3:1:j_id11:0:j_id12:1:j_id17">Version B1</td> </tr> <tr></tr> <tr></tr> <tr> <td id="j_id3:1:j_id11:1:j_id22"> Product B1</td> <td id="j_id3:1:j_id11:1:j_id24">NO VERSIONS</td> </tr> <tr></tr> <tr></tr> <tr> <td id="j_id3:2:j_id27">Company C</td> <td id="j_id3:2:j_id29">NO PRODUCTS</td> <td id="j_id3:2:j_id31">NO VERSIONS</td> </tr> </tbody> </table>
Should these empty rows be rendered, or this is a bug?
Any ideas on how to proceed?
-
11. Re: rich:datatable rowspan using rich:subtable
ilya_shaikovsky May 7, 2010 7:48 AM (in response to deadlock_gr)Reproduced the reason and played much with additional conritions and code variants. That seems like real issue with tables encoding logic. The most worst thign that you found it only after last 3.3.x release :/ And it's really strange that nobody tried such scenario in the past :/.. There seems a problem when the table itself opens TR element for columns rendering and then it should delegate actual td's output to columns.. but columns or column group not rendered in your case so the further encoding should be done by subtable. But subtable has to be oncoded at separate row by design - so table closes TR without any output and renders new one for subtable. The same issue with nested subtables. Variant with 2 level structure looked fine because there was only one empty TR rendered at the last line(because of your testing data) - so it was there but not visible using this data
Actually I do not see workaround for now except (very ugly) removing empty tr's with js after table rendered, or patching the actual richfaces code with some additional logic and building custom jars if this suitable for you.
-
12. Re: rich:datatable rowspan using rich:subtable
deadlock_gr May 7, 2010 11:03 AM (in response to ilya_shaikovsky)Thanks Ilya,
At least now I know I wasn't doing something profoundly wrong.
In any case, I think that this is an important feature for the rich:datatable to have. And even if my approach worked, I am sure that there should be a better solution than having to play with rendered and rowKeyVar.
Something like this is a first (fast) idea:
<rich:datatable value="#{company}" var ="comp" subValue="#{comp.products}" subVar="prod" subSubValue="#{prod.versions}" subSubVar="ver">
I will give it some thought and might come back for discussion.
-
13. Re: rich:datatable rowspan using rich:subtable
deadlock_gr May 27, 2010 11:31 AM (in response to deadlock_gr)Should I create a Jira issue? Or is this being taken care of?
-
14. Re: rich:datatable rowspan using rich:subtable
ilya_shaikovsky Jun 7, 2010 3:12 PM (in response to deadlock_gr)sorry.. forgot to update.. jira.jboss.org/jira/browse/RF-8642