How to achieve complex header in Bootsfaces datatable - jsf

I am using Bootsfaces datatable to display my data. However, I want to achieve complex header as shown here: https://datatables.net/examples/basic_init/complex_header.html
I tried to add <th rowspan> and <th colspan> directly under header facet in the first dataTableColumn, but that have a ugly empty row at the top.
I also tried to add the whole header facet under <b:dataTable...> tag, before the fist <b:dataTableColumn>, but that header code won't be generated into the html. Any other suggestions? I do not want to switch to primefaces or richfaces as my framework as been fixed.
My code that trying to achieve the complex header looks like below:
<b:dataTable value="#{podStatusListBean.podStatusBeanList}"
var="podStatus"
id="podStatuses">
<b:dataTableColumn footer-style='background-color:orange'
footer-styleclass="{podStatusListBean.footerVisibility}">
<f:facet name="header">
<tr>
<th rowspan="2">Name</th>
<th colspan="2">HR Information</th>
<th colspan="3">Contact</th>
</tr>
</f:facet>
...

This is a new feature we've added to the next BootsFaces version (probably 1.2). As of June 15, 2017, the current version of BootsFaces 1.1.1 only supports complex headers on a per-column basis.
Complex headers per column (supported since BootsFaces 0.8.0):
Add a header facets to the <b:dataTableColumn />, pretty much the way you tried. But keep in mind that BootsFaces already generates the <tr> and <th> tags, so you can nest them a second time. But you can do something like this:
<b:dataTableColumn>
<f:facet name="header">
<ul
style="margin-bottom: 0; list-style-type: none; padding-left: 0">
<li>Price</li>
<li>Engine Power</li>
</ul>
</f:facet>
€ #{car.price}
<br />
#{car.enginePowerKW} KW (#{car.enginePower} hp)
</b:dataTableColumn>
</b:dataTable>
More complex headers (will be supported beginning with BootsFaces 1.2.0):
Add a header facet to the surrounding <b:dataTable /> tag. In this case you're responsible for defining the correct number of table headers. If you skip one, you'll be rewarded by a JavaScript error. In many cases it will even go by unnoticed, but the initialization of the datatable is incomplete, so you'd rather be careful.
<b:dataTable value="#{carPool.carPool}"
var="car"
page-length="5"
page-length-menu="5,10,20">
<f:facet name="header">
<tr>
<th rowspan="2">Car</th>
<th colspan="2">Appearance</th>
<th colspan="2">Technical Data</th>
</tr>
<tr>
<th>Color</th>
<th>Year</th>
<th>Price</th>
<th>Power</th>
</tr>
</f:facet>
<b:dataTableColumn>
#{car.brand} #{car.type}
</b:dataTableColumn>
<b:dataTableColumn value="#{car.color}" />
<b:dataTableColumn value="#{car.year}" order="asc" />
<b:dataTableColumn value="#{car.price}" />
<b:dataTableColumn value="#{car.enginePower}"/>
</b:dataTable>

Related

Primefaces - How to show and hide two different `panel` components in one location

I need your help in showing and hiding two different panel components in one location. Currently in the page at the top, I am allowing the user to select one choice from the selectOneRadio component.
Below the selectOneRadio component, I am placing two different panel components where I am using the rendered attribute to show or hide the panel based on the selection. For example if the user selects the first option, the first panel will be shown and the second will be hidden and if he chose the second option, the first panel component will be hidden and the second will be shown.
However, the issue which I am facing is if the user selects the second option that the first panel will be hidden and there will be a huge space as I am placing panelGrid components and inputText components under the first panel and below it, the second panel will be shown. So how can I make the second panel to be shown in the location of the first panel.
Here is the JSF code:
<table border="0" cellspacing="0" width="100%">
<tr>
<td>
<p:outputLabel value="Please Select a Request Type:"/>
</td>
</tr>
<tr>
<p:selectOneRadio id="request" layout="pageDirection" value="#{user.requestType}">
<td width="50%">
<f:selectItem itemLabel="Certificates for Other" itemValue="O"/>
</td>
<td width="50%">
<f:selectItem itemLabel="Certificates for Banks" itemValue="B"/>
</td>
<p:ajax event="change" update="#form" listener="#{user.firstToggle}"/>
</p:selectOneRadio>
</tr>
</table>
<p:panel id="toggleable" header="Certificates for Other" toggleable="true" rendered="#{user.firstTogg}" widgetVar="panel" style="margin-bottom:20px">
<table border="0" cellspacing="0" cellpadding="2">
<tr>
<td height="100%">
<p:selectOneMenu label="c_e_language_hr" id="c_e_language_hr" disabled="#{user.firstTogg}" value="#{user.employmentCertificateLanguageHr}">
<f:selectItem itemLabel="Please Select a Language" itemValue="F"/>
<f:selectItems value="#{user.ceLangDesc}" var="celang" itemLabel="#{celang.langDesc}" itemValue="#{celang.langCd}"/>
</p:selectOneMenu>
</td>
</tr>
</table>
</p:panel>
<p:panel id="toggleable1" header="Certificates for Banks" toggleable="true" rendered="#{user.secondToggle}" widgetVar="panel1" style="margin-bottom:15px">
</p:panel>

JSF with CDI dataTable var is empty

I'm trying to loop over a list and print out some properties using a JSF dataTable as follows:
<?xml version="1.0" encoding="UTF-8"?>
<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">
<h:dataTable value="#{clubAdministrationController.members()}" var="member">
<f:facet name="header">
<h:outputText value="Leden" />
</f:facet>
<h:column>
<f:facet name="header">
<h:outputText value="Voornaam" />
</f:facet>
<h:outputText value="#{member.firstName}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Achternaam" />
</f:facet>
<h:outputText value="#{member.lastName}"/>
</h:column>
<h:column>
<h:outputLink id="bewerklid#{member.username}" value="bewerklid/#{member.username}">Wijzig</h:outputLink>
</h:column>
</h:dataTable>
</html>
and I get this result:
<table>
<thead>
<tr>
<th colspan="3" scope="colgroup">Leden</th></tr>
<tr>
<th scope="col">Voornaam</th>
<th scope="col">Achternaam</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td><a id="j_idt12:0:bewerklid" name="j_idt12:0:bewerklid" href="bewerklid/">Wijzig</a></td>
</tr>
<tr>
<td></td>
<td></td>
<td><a id="j_idt12:1:bewerklid" name="j_idt12:1:bewerklid" href="bewerklid/">Wijzig</a></td>
</tr>
</tbody>
</table>
The dataTable iterates the correct amount of times because I have 2 members, but all fields are empty.
When I debug the Java, the members() method returns a list with correctly filled instances and when I print out the values directly the correct values are printed.
#{clubAdministrationController.members().get(0).firstName} <!--displays values correctly -->
When I print out the class name of the member var I get Member$Proxy$_$$_WeldClientProxy
#{member['class'].simpleName} <!-- prints Member$Proxy$_$$_WeldClientProxy -->
I think this suggests that something is going wrong with the dependency injection. I'm using CDI and I know that Weld is a CDI-implementation, and that CDI doesn't inject the actual class, but a proxy-class. I guess a proxy-class is instantiated but the fields must somehow still be copied from the source instance.
I just started learning JSF and CDI, so my question is "what do I have to change to make the dataTable display my Members?"
This is my ClubAdministrationController, when I debug it, the list is filled with my two members:
#Named
#RequestScoped
public class ClubAdministrationController {
#Inject
private MemberDao memberDao;
public List<Member> members() {
List<Member> members = memberDao.getMembers();
return members;
}
}
Since member is a Weld-Proxy you seem to have a class that is #Named member somewhere. (implicit or explicit)
Your data table is now iterating over the correct list (therefore resulting in the correct row count), but always refering to a named class, which does not have the proper values. Most Likely, you have a certain Annotation on your Member.class, which then causes a named WeldProxy (which is empty) to be generated, when you use the el-expression #{member}
(this expression will win against the datatable var member)
Here, you are refering to the instance of member inside the list member():
#{clubAdministrationController.members().get(0).firstName} <!--displays values correctly -->
Here you are refering to the named weld-proxy #{member} - as the class-attribute shows:
#{member['class'].simpleName} <!-- prints Member$Proxy$_$$_WeldClientProxy -->
Changing your var="member" to var="m" and use m.firstName should solve your problem.
To tell you what's wrong with your Member.class, you should include that Code as well.

<p:row> renders incorrect result

I have been working on this problem from last two days. I went through the apis possibly I could refer to but no luck.
I have been using ui:repeat as jsf facelet to render data with rows and columns
Code for reference
<ui:repeat var="pendingRequestItem" value="#{oqHomeController.allRequests}" > --JSF
<p:row rendered="#{oqHomeController.renderPendingRequest}> -- PRIMEFACES FOR ROW
<td><h:outputText value="#{pendingRequestItem.title}" /></td>
<td><h:outputText value="#{oqHomeController.pendingCount}" /></td>
</p:row>
</ui:repeat>
And the above code is resulting in the following which is very strange.
<tbody>
<td>Request for Quote 1</td>
<td>1</td>
<td>DTHEME1</td>
<td>4</td>
</tbody>
I hope it should be
<tbody>
<tr>
<td>Request for Quote 1</td>
<td>1</td>
</tr>
<tr>
<td>DTHEME1</td>
<td>4</td>
</tr>
</tbody>
Please help thanks.
Have you tried <p:dataTable> it seems that is what you are looking for:
<p:dataTable var="pendingRequestItem" value="#{oqHomeController.allRequests}">
<p:column>
<h:outputText value="#{pendingRequestItem.title}"/>
</p:column>
<p:column>
<h:outputText value="#{oqHomeController.pendingCount}"/>
</p:column>
</p:dataTable>

p:dataList rendering in Internet Explorer 8

my page contains a data list within another data list. The outer data list simulates an accordion panel, while the inner data list renders my dynamic columns.
Everything works fine, but Internet Explorer 8 behaves differently in respect of Firefox and Chrome, because in the resulting html it renders some empty objects that leaves a blank space before data.
The screenshots show the differences between Explorer 8 and Firefox.
Firefox generated HTML:
Explorer 8 generated HTML:
Firefox rendering:
Explorer 8 rendering:
Here is the code:
<p:dataList id="data" styleClass="myDataList" value="#{bean.getAnag(idSito)}" var="tipologia" itemType="disc" type="definition">
<div class="ui-accordion ui-widget ui-helper-reset ui-hidden-container tabAccordion" style="width: 100%;">
<table id="accordionFake#{idSito}" border="1" class="table-din-col" style="display: none; margin-bottom: 10px;">
<!-- HEADERS -->
<tr class="table-din-col-titolo">
<td style="padding: 4px;">
<h:outputText value="Codice" />
</td>
<td style="padding: 4px;">
<h:outputText value="Descrizione" />
</td>
<td style="padding: 4px;">
<h:outputText value="CodiceAgg" />
</td>
<td style="padding: 4px;">
<h:outputText value="Pos" />
</td>
<p:dataList value="#{bean.buildColumns(idSito)}" var="colDin" type="definition">
<td>
<h:outputText value="#{colDin.header}" />
</td>
</p:dataList>
</tr>
<!-- HEADERS -->
<!-- ROWS BUILDING -->
<p:dataList id="dataL" var="rilevazione" selectionMode="single"
value="#{bean.getLsLoc(idSito)}" type="definition">
<tr class="table-din-col-righe">
<td class="table-din-col-colonne">
<h:outputText id="codice" value="#{rilevazione.codice}" />
</td>
<td class="table-din-col-colonne">
<h:outputText id="desc" value="#{rilevazione.descrizione}" />
</td>
<td class="table-din-col-colonne">
<h:outputText id="codSnam" value="#{rilevazione.codiceAgg}" />
</td>
<td class="table-din-col-colonne">
<h:outputText id="pos" value="#{rilevazione.pos}" />
</td>
<p:dataList value="#{bean.buildColumns(idSito)}" var="colDin" type="definition">
<td class="table-din-col-colonne">
<h:outputText value="#{colDin.property.valore}" />
</td>
</p:dataList>
</tr>
</p:dataList>
<!-- ROWS BUILDING -->
</table>
</div
</p:dataList>
How can I instruct ie8 to correctly render the data lists?
Thanks in advance.
It look like you was using the wrong component for the purpose, or are at least not understanding/familiar with basic HTML.
The <p:dataList> gives you the option to generate a HTML <ul><li> (unordered list), <ol><li> (ordered list) or <dl><dt><dd> (definition list).
However, you seem to be after generating a plain vanilla HTML <table><tr><td> with all cells hardcoded. You have nested a <p:dataList type="definition"> inside <tr> which would only generate <dl><dt><dd> elements inplace where <td> elements are expected. This only ends up in illegal HTML syntax. IE is rather sensitive to that.
You should replace the nested <p:dataList type="definition"> components by <ui:repeat>. It doesn't generate any HTML and your HTML will end up syntactically valid (although I wonder how it makes sense to have a <dl><dt><dd><table>, after all, I suggest to learn basic HTML as well, so that you can better understand which JSF components to pick for the purpose).

Conditionally creating table rows JSF2

I want to create a table which display a list of values in several rows, each row should contains only 3 columns.
I can create this by using JSTL but not using JSF. I am suspecting that it is xhtml related issue, not a problem in JSP, xhtml is very strict about the elements formation. Is there a way to achieve this?
Using JSTL:
<c:forEach var="book" value="${bookBean.bookList}" varStatus="bookStatus">
<c:if test="${bookStatus.index eq 0 or bookStatus.index mod 3 eq 0}">
<tr>
</c:if>
<td>
<table>
<tr>
<td>#{book.bookId}</td>
<td>#{book.bookName}</td>
<td>#{book.price}</td>
<td>#{book.author}</td>
</tr>
</table>
</td>
<c:if test="${bookStatus.count mod 3 eq 0}">
</tr>
</c:if>
</c:forEach>
Using JSF:
<ui:repeat var="book" value="#{bookBean.bookList}" varStatus="bookStatus">
<ui:fragment rendered="#{bookStatus.first or bookStatus.index mod 3 eq 0}">
<tr> <!-- Here i am getting an error saying closing tr missed.--->
</ui:fragment>
<td>
<table>
<tr>
<td>#{book.bookId}</td>
<td>#{book.bookName}</td>
<td>#{book.price}</td>
<td>#{book.author}</td>
</tr>
</table>
</td>
<ui:fragment rendered="#{(bookStatus.index+1) mod 3 eq 0}">
</tr>
</ui:fragment>
</ui:repeat>
This is actually not easy to do without using some component library (richfaces I know for a fact that has a component that does this.. rich:dataGrid..)
Here's a solution I found a while back to solve this issue... (I'm not a big fan of component libraries myself... ).. it's not the most elegant solution.. but it does the trick..
<table>
<tr>
<ui:repeat var="book" value="#{bookBean.bookList}" varStatus="bookStatus">
<td>
<table>
<tr>
<td>#{book.bookId}</td>
<td>#{book.bookName}</td>
<td>#{book.price}</td>
<td>#{book.author}</td>
</tr>
</table>
</td>
<h:outputText value="</tr><tr>" escape="false" rendered="#{(bookStatus.index + 1 ) mod 3 eq 0}"/>
</ui:repeat>
</tr>
</table>
As #FMQ has mentioned, try to use a JSF component library. Primefaces could be a good option, checkout the Demo page.

Resources