Reputation: 169
I'm using a Primefaces "Datatable" with a "Subtable".
I've got some header columns with two row.
In the first row, I've got 5 header columns. In the second row, I've got 8 header columns.
On the first level columns of my datatable I want to display "Item"s informations in five columns.
On the second level and when I display the selected item's child, I want to display the item's status informations (in 8 columns).
The status informations are contained in a subtable.
I wanted to packed some columns of my header second row, under columns of my header first row.
To make it possible, I've referenced on the first row column of the header, the attribute "colspan" with the value "3" and on another column with the value "2".
The problem is it also packs my data value columns of my first level rows. This means I have 8 columns to fill instead of 5 and they are packed. I just want to have 5 columns for my first level and 8 for my second level (status informations).
Is is possible to only add colspan on the header columns and not in the body ?
Here is a sample of my code :
<p:columnGroup type="header">
<p:row>
<p:column>
</p:column>
<p:column headerText="#{bundle.form_name}" filterBy="#{item.name}"
sortBy="#{item.name}" colspan="3">
</p:column>
<p:column headerText="#{bundle.form_designation}"
style="width:140px;" filterBy="#{item.designation}"
sortBy="#{item.designation}" colspan="2">
</p:column>
<p:column headerText="#{bundle.form_status}"
filterBy="#{item.status}"
filterOptions="#{itemStatusListBean.options}">
</p:column>
<p:column headerText="#{bundle.form_date}"
filterBy="#{item.statusDate}" sortBy="#{item.statusDate}">
</p:column>
</p:row>
<p:row>
<p:column />
<p:column headerText="Status" style="width:25px;" />
<p:column headerText="Type" style="width:25px;" />
<p:column headerText="Marché" style="width:25px;" />
<p:column headerText="Groupe" />
<p:column headerText="Produit" />
<p:column headerText="Désignation Produit" />
<p:column headerText="EAN" />
</p:row>
</p:columnGroup>
<p:column style="width:4%">
<p:rowToggler>
</p:rowToggler>
</p:column>
<p:column>
<h:outputText value="#{item.name}" />
</p:column>
<p:column>
<h:outputText value="#{item.designation}" />
</p:column>
<p:column>
<h:outputText value="#{item.status.label}" />
</p:column>
<p:column>
<h:outputText value="#{item.statusDate}">
<f:convertDateTime pattern="dd/MM/yyyy" timeZone="Europe/Paris" />
</h:outputText>
</p:column>
<p:rowExpansion>
<p:subTable var="status" value="#{item.status}">
<p:column>
</p:column>
<p:column>
</p:column>
<p:column>
</p:column>
<p:column>
</p:column>
<p:column>
</p:column>
<p:column>
</p:column>
<p:column>
</p:column>
</p:subTable>
</p:rowExpansion>
</p:dataTable>
Upvotes: 4
Views: 19122
Reputation: 169
Okay, so now I've found the solution.
First of all, the solution implies a little bit of Primefaces tweak. In fact, you need to enable the possibility to add the attribute "colspan" to the "column" tag included inside a DataTable.
To make it possible, you need to create this following package : "org.primefaces.component.datatable" and create a class named "MyDataTableBeanRenderer" that will extends the actual "DataTableBeanRenderer".
In this class, you will need to "Override" the methods that handles the DataTable's body cells rendering (encodeRegularCell), the row expansion rendering and the paginator rendering if you use one.
You will also have to add a method that will retrieve the number of rows contained in the
second row of your header column group. If this second level of the dataTable contains more row than the second, then the current "td" or "th" colspan (depending on the method) will be adjusted.
In each method, check where "getMaximumNumberOfColumns" method is called.
Now, here is the corresponding Java Code :
@Override
protected void encodeRegularCell(FacesContext context, DataTable table, Column column, String clientId,
boolean selected) throws IOException {
final ResponseWriter writer = context.getResponseWriter();
final boolean selectionEnabled = column.getSelectionMode() != null;
final String style = column.getStyle();
String styleClass = "";
if (selectionEnabled) {
styleClass = DataTable.SELECTION_COLUMN_CLASS;
} else if (column.getCellEditor() != null) {
styleClass = DataTable.EDITABLE_COLUMN_CLASS;
}
styleClass = column.getStyleClass() == null ? styleClass : styleClass + " " + column.getStyleClass();
writer.startElement("td", null);
writer.writeAttribute("role", "gridcell", null);
if (column.getColspan() != 1) {
writer.writeAttribute("colspan", column.getColspan(), null);
}
if (style != null) {
writer.writeAttribute("style", style, null);
}
if (!isValueBlank(styleClass)) {
writer.writeAttribute("class", styleClass.trim(), null);
}
if (selectionEnabled) {
writer.startElement("div", null);
writer.writeAttribute("class", DataTable.COLUMN_CONTENT_WRAPPER, null);
encodeColumnSelection(context, table, clientId, column, selected);
writer.endElement("div");
} else {
writer.startElement("div", null);
writer.writeAttribute("class", DataTable.COLUMN_CONTENT_WRAPPER, null);
column.encodeAll(context);
writer.endElement("div");
}
writer.endElement("td");
}
@Override
protected void encodePaginatorMarkup(FacesContext context, DataTable table, String position, String tag,
String styleClass) throws IOException {
final ResponseWriter writer = context.getResponseWriter();
if (!table.isPaginatorAlwaysVisible() && table.getPageCount() <= 1) {
return;
}
final String id = table.getClientId(context) + "_paginator_" + position;
writer.startElement("tr", null);
writer.startElement(tag, null);
writer.writeAttribute("id", id, null);
writer.writeAttribute("class", styleClass, null);
final Integer rowsCount = getMaximumNumberOfColumns(table);
if (rowsCount == null || (rowsCount != null && rowsCount < table.getColumnsCount())) {
writer.writeAttribute("colspan", table.getColumnsCount(), null);
} else {
writer.writeAttribute("colspan", rowsCount, null);
}
final String[] elements = table.getPaginatorTemplate().split(" ");
for (final String element : elements) {
final PaginatorElementRenderer renderer = paginatorElements.get(element);
if (renderer != null) {
renderer.render(context, table);
} else {
writer.write(element + " ");
}
}
writer.endElement(tag);
writer.endElement("tr");
}
@Override
protected void encodeRowExpansion(FacesContext context, DataTable table) throws IOException {
final ResponseWriter writer = context.getResponseWriter();
final Map<String, String> params = context.getExternalContext().getRequestParameterMap();
final int expandedRowIndex = Integer.parseInt(params.get(table.getClientId(context) + "_expandedRowIndex"));
final String rowIndexVar = table.getRowIndexVar();
table.setRowIndex(expandedRowIndex);
if (rowIndexVar != null) {
context.getExternalContext().getRequestMap().put(rowIndexVar, expandedRowIndex);
}
writer.startElement("tr", null);
writer.writeAttribute("style", "display:none", null);
writer.writeAttribute("class", DataTable.EXPANDED_ROW_CONTENT_CLASS + " ui-widget-content", null);
writer.startElement("td", null);
final Integer rowsCount = getMaximumNumberOfColumns(table);
// Fix the number of columns of the second level with its appropriate
// number of rows
if (rowsCount == null || (rowsCount != null && rowsCount < table.getColumnsCount())) {
writer.writeAttribute("colspan", table.getColumnsCount(), null);
} else {
writer.writeAttribute("colspan", rowsCount, null);
}
table.getRowExpansion().encodeAll(context);
writer.endElement("td");
writer.endElement("tr");
table.setRowIndex(-1);
}
// get the maximum number of rows if the datatable can be expanded
private Integer getMaximumNumberOfColumns(DataTable table) {
Integer count = null;
// If the datatable contains a column group it means it can be expanded
// and contains 2 levels
if (table.getChildren().get(0) != null && table.getChildren().get(0) instanceof ColumnGroup) {
final ColumnGroup columnGroup = (ColumnGroup) table.getChildren().get(0);
if (columnGroup.getChildren().get(1) != null && columnGroup.getChildren().get(1) instanceof Row) {
final Row row = (Row) columnGroup.getChildren().get(1);
if (row.getChildren() != null) {
count = row.getChildren().size();
}
}
}
return count;
}
And here is the "dataTable" part contained in my view that fits the behaviour treated by the function that were overriden.
<p:columnGroup type="header">
<p:row>
<p:column >
</p:column>
<p:column headerText="#{bundle.form_name}" filterBy="#{item.name}"
sortBy="#{item.name}" colspan="3">
</p:column>
<p:column headerText="#{bundle.form_designation}"
style="width:140px;" filterBy="#{item.designation}"
sortBy="#{item.designation}" colspan="2">
</p:column>
<p:column headerText="#{bundle.form_status}"
filterBy="#{item.status}"
filterOptions="#{itemStatusListBean.options}">
</p:column>
<p:column headerText="#{bundle.form_date}"
filterBy="#{item.statusDate}" sortBy="#{item.statusDate}">
</p:column>
</p:row>
<p:row>
<p:column />
<p:column headerText="Status" />
<p:column headerText="Type" />
<p:column headerText="Marché" />
<p:column headerText="Groupe" />
<p:column headerText="Produit" />
<p:column headerText="Désignation Produit" />
<p:column headerText="EAN" />
</p:row>
</p:columnGroup>
<p:column style="width:4%">
<p:rowToggler/>
</p:column>
<p:column colspan="3">
<h:outputText value="#{item.name}" />
</p:column>
<p:column colspan="2">
<h:outputText value="#{item.designation}" />
</p:column>
<p:column>
<h:outputText value="#{item.status.label}" />
</p:column>
<p:column>
<h:outputText value="#{item.statusDate}">
<f:convertDateTime pattern="dd/MM/yyyy" timeZone="Europe/Paris" />
</h:outputText>
</p:column>
<p:rowExpansion>
<p:dataTable id="relationDataTable"
widgetVar="relationDataTable" var="relation"
value="#{relationDataTableBean.dataModel}"
rows="10">
<p:column></p:column>
<p:column><h:outputText value="#{relation.status}"/></p:column>
<p:column><h:outputText value="#{relation.type}"/></p:column>
<p:column><h:outputText value="#{relation.market}"/></p:column>
<p:column><h:outputText value="#{relation.group}"/></p:column>
<p:column><h:outputText value="#{relation.produit}"/></p:column>
<p:column><h:outputText value="#{relation.desiProduit}"/></p:column>
<p:column><h:outputText value="#{relation.ean}"/></p:column>
</p:dataTable>
</p:rowExpansion>
So basically, just put a colspan value to your first row header columns that must packed header columns from the second level.
In this case, check the columns that handles the "name" and the "designation".
<p:column headerText="#{bundle.form_name}" filterBy="#{item.name}"
sortBy="#{item.name}" colspan="3">
</p:column>
<p:column headerText="#{bundle.form_designation}"
style="width:140px;" filterBy="#{item.designation}"
sortBy="#{item.designation}" colspan="2">
</p:column>
Then, add the same "colspan" attribute and value to the corresponding columns index, but in the dataTable body (columns aimed at displaying the data of on object) :
<p:column colspan="3">
<h:outputText value="#{item.name}" />
</p:column>
<p:column colspan="2">
<h:outputText value="#{item.designation}" />
</p:column>
My implementation, may present some defaults in some situations, but it works fine most of the time. I hope it will help if you encounter the same problem one day.
Upvotes: 2
Reputation: 1539
Try to insert a <h:panelGrid>
or another nested <p:dataTable>
inside the <p:rowExpansion>
.
It should create another table nested inside the table cell (with colspan=5), with eight columns on the nested cell, leaving the main table with only five columns.
HTML tables are rendered with the largest amount of columns among all rows (including headers) check http://www.w3.org/TR/html401/struct/tables.html#h-11.2.4.3
your rowExpansion would look like this:
<p:rowExpansion>
<p:dataTable>
<p:columnGroup>
<p:row>
<p:column />
<p:column headerText="Status" style="width:25px;" />
<p:column headerText="Type" style="width:25px;" />
<p:column headerText="Marché" style="width:25px;" />
<p:column headerText="Groupe" />
<p:column headerText="Produit" />
<p:column headerText="Désignation Produit" />
<p:column headerText="EAN" />
</p:row>
</p:columnGroup>
<p:column></p:column>
<p:column></p:column>
<p:column></p:column>
<p:column></p:column>
<p:column></p:column>
<p:column></p:column>
<p:column></p:column>
</p:dataTable>
</p:rowExpansion>
Upvotes: 0