Create a dynamic table from a java.util.Map - jsf

I'm developing a web application in JSF 2.0. In my application I need a table for viewing presences.
I have a Map<Date, List<Presence>> in my 'PresenceService' bean.
The Presence object has a Person object (with name and surname) and a boolean present/not present.
I'd like to create a table that looks like this:
monday tuesday wednesday ...
Name Person 1 present not present present ...
Name Person 2 present present present ...
... ... ... ... ...
Which JSF components could I use to create such a table? Or should I not be using a Map for this? I tried creating a table myself with <ui:repeat>'s but failed to do so.
As wel the colums as the rows can be dynamic since the user can choose a period and a range of persons.
EDIT: solution (see answer Balus C)
This works like a charm:
<table>
<tr>
<th>Name</th>
<ui:repeat value="#{aanwezigheidController.siAanwezigheidService.datums}" var="datumHeader">
<th>
<h:outputText value="#{datumHeader}">
<f:convertDateTime pattern="dd/MM/yyyy" />
</h:outputText>
</th>
</ui:repeat>
</tr>
<ui:repeat value="#{aanwezigheidController.siAanwezigheidService.aanwezigheidSiRijen}" var="aanwRij">
<tr>
<td>#{aanwRij.persoon.naam} #{aanwRij.persoon.voornaam}</td>
<ui:repeat value="#{aanwezigheidController.siAanwezigheidService.datums}" var="datumCell">
<td>
<h:outputText value="aanwezig" rendered="#{aanwRij.aanwezighedenMap[datumCell].aanwezig}" />
<h:outputText value="afwezig" rendered="#{!aanwRij.aanwezighedenMap[datumCell].aanwezig}" />
</td>
</ui:repeat>
</tr>
</ui:repeat>
</table>

A double nested <ui:repeat> should be fine. The standard JSF implementation does not offer something like <h:columns> to represent dynamic columns, but component libraries RichFaces and PrimeFaces have respectively <rich:columns> and <p:columns> for exactly this purpose. You may want to take a look at it.
With alone a Map<Date, List<Presence>>, it is not possible to pick a specific person to present the row data for all columns. You basically need a Map<Date, Map<Person, List<Presence>>, or a separate List<Date> representing the dynamic columns and a separate List<Presence> where the Presence in turn has Person and Map<Date, Boolean> properties so that a specific date can be picked for the columns.

Related

Summary row JSF DataTable

I have to put in summary many columns summarizing the results,
and in jsf datatable i cant do it, someone know how can i do it? without use primefaces
im got this result
<h:dataTable id="tableResult" value="#{managedBean.dataModel}"
var="obj" rows="15" layout="block" styleClass="table">
<h:column>
<f:facet name="header">Total abandonada</f:facet>
<h:outputText value="#{obj.totalAbandon}">
</h:outputText>
</h:column>
<h:column>
<f:facet name="header">Total</f:facet>
<h:outputText value="#{obj.total}" />
</h:column>
<h:column>
<f:facet name="header"> Atendidas %</f:facet>
<h:outputText value="#{obj.percentualAnswered}%" />
</h:column>
<h:column>
<f:facet name="header">Abandonos %</f:facet>
<h:outputText value="#{obj.percentualAbandon}%" />
</h:column>
<f:facet name="footer">#{obj.suumary}
</f:facet>
</h:dataTable>
to got this result im using
<f:facet name="footer">Total : 2</f:facet>
but i want this result
<tr>
<td>Total : 2</td>
<td>Total answered : 1</td>
<td>Total abandon : 1</td>
</tr>
</tfoot>
i have been tried use 2 footer facet and doesnt work
A plain JSF h:datatable does not have the notion of something like a summary per group of rows built in. So if this is what you want, you need to either switch to e.g. PrimeFaces or add the summary row to your model in the right place and be creative with the CSS for the rows and the content.
If you want a footer for the full datable, the footer facet is the right thing (a summary of the datatable). But in this footer you cannot use the variable you assigned in the var attribute, in your case obj Think of it, which obj should be used? The first? Second? Last? All (each)? So add a field to the managedBean that contains the 'summary' and display that.
<f:facet name="footer">#{manageBean.summary}</f:facet>
If summary is a list, you can iterate over it like mentioned in Iterate over nested List property inside h:datatable
The html you'll end up is
<tfoot>
<tr>
<td>
.... your content of the nested list
</td>
</tr>
</tfoot>
This contnt can be either a table, list, div's or whatever you want.

How do I get h:outputText inside of a ui:repeat nested in h:dataTable to update when the datatable is updated?

So the relevant sections of my code is:
<h:panelGroup id="pnlGrp" style="padding:10px" width="100%">
<div>
<h:dataTable id="availableCrList"
value="#{searchData.availableCrList}"
var="avail"
varStatus="thisVarStatus" rows="#{searchData.rowsPerPage}"
sortColumn="#{searchData.crSortColumnName}"
sortAscending="#{searchData.crAscending}" style="width:100%;">
<h:column>
<ui:repeat value="#{avail.crRsnCdList}"
var="crRsnCd"
varStatus="status">
<h:outputText value="#{crRsnCd}<br />"
title="#{avail.crRsnDescList[status.index]}"
escape="false"/>
</ui:repeat>
</h:column>
</h:dataTable>
</div>
</h:panelGroup>
I'm working inside a legacy application and my goal is to display a list of codes which indicate reasons why a given item in this table might be completed, or cancelled, et cetera. The title is converted into a hovering tooltip which displays the description for each of these codes.
Now, I managed to get this working for singular codes no problem, but since switching from a String to a List of strings it's been a nightmare trying to get this to work.
Right now with the above code it displays the codes correctly the first time, but when I update the datatable by searching for a new value all the other columns (not shown) are correctly displayed while the RsnCd column continues to display the same data from the first search.
As an example, the first time I search for records the datatable might pull up:
Row1:A1
Row2:A1
Row3:A1
A3
Row4:A1
The second time I search for data I would expect to see only:
Row1:
Row2:
Row3:
Row4:
Row5:
Row6:
Row7:
But instead I get:
Row1:A1
Row2:A1
Row3:A1
A3
Row4:A1
Row5:
Row6:
Row7:
Really not sure if I'm explaining this adequately/understandably.
I solved this issue by changing
<ui:repeat value="#{avail.crRsnCdList}"
var="crRsnCd"
varStatus="status">
<h:outputText value="#{crRsnCd}<br />"
title="#{avail.crRsnDescList[status.index]}"
escape="false"/>
</ui:repeat>
To:
<ice:column>
<ice:repeat value="#{avail.crRsnCdList}"
varStatus="status">
<ice:outputText value="#{avail.crRsnCdList[status.index]}<br />"
title="#{avail.crRsnDescList[status.index]}"
escape="false"/>
</ice:repeat>
</ice:column>
I tried getting rid of the value but it stopped displaying anything.

How to display Label and Value in h:outputText

I want to display datacenter id and datacenter Name in this case 1000 and DC1.
I made this complex JSF code but it turns out that I cannot display the id as Value and Datacenter name as label. Something like this:
<f:selectItems value="#{ZoneProfileTabGeneralController.listDatacenters}" var="datacenters" itemValue="#{datacenters.datacenterid}" itemLabel="#{datacenters.datacentername} - #{datacenters.datacenterid}" />
This is the test that I made.
<h:outputText value="#{ZoneProfileTabGeneralController.DatacenterNameId(ud.datacenterId)} - #{ud.datacenterId}"
Is there any way to display the id as hidden value and the name as label. But when I submit the JSF page to send back only the datacenter id?
EDIT
<tr>
<td>Datacenter ID</td>
<td>
<h:outputText value="#{ud.datacenterId}"
rendered="#{not ZoneProfileTabGeneralController.editable}" />
<h:selectOneMenu value="#{ud.datacenterId}" label="#{ZoneProfileTabGeneralController.DatacenterNameId(ud.datacenterId)} - #{ud.datacenterId}" rendered="#{ZoneProfileTabGeneralController.editable}">
<f:selectItems value="#{ZoneProfileTabGeneralController.listDatacenters}" var="datacenters" itemValue="#{datacenters.datacenterid}" itemLabel="#{datacenters.datacentername} - #{datacenters.datacenterid}" />
</h:selectOneMenu>
</td>
</tr>

jsf repeat inside datatable

I'm using datatable and i get number of columns dynamically. I tried to put repeat inside like this way:
<h:dataTable value="#{movieUserBean.sits}" var="row"
rowClasses="oddRows,evenRows" headerClass="header"
styleClass="table" cellpadding="5" cellspacing="0">
<ui:repeat value="#{row}" var="sit">
<h:column>
<h:selectBooleanCheckbox value= "#{movieUserBean.checked[sit.id]}"/>
</h:column>
</ui:repeat>
Which sits is a two dimensions array, my thought was that datatable should loop over the sits rows and repeat loops over every value inside every row (which is an object named Sit with get method: getId).
The problem is that I get an empty table. Seems like var "sit" is not getting value.
Can the problem be the fact that datatable ignores any elements who's not in column scope?
ui:repeat is called before the render response phase, i suggest you to use DynamicColumns of primefaces http://www.primefaces.org/showcase/ui/datatableDynamicColumns.jsf
A simple solution would be
<table>
<ui:repeat value="#{movieUserBean.sits}" var="row">
<tr>
<ui:repeat value="#{row}" var="sit">
<td><h:selectBooleanCheckbox value= "#{movieUserBean.checked[sit.id]}"/></td>
</ui:repeat>
</tr>
</ui:repeat>
</table>
If you have variable columns per row it might mess up with css styles. For example 5 columns on row one and 3 columns on row 2, how would you style them. The way i see it you want to show seats in a theater occupied with a checkbox.
You can try using ui:repeat's with ul,li or div's instead of going with the table. approach.

JSF 2 Composite Component rendering problem

My composite component (cc) creates an inputText-Field. The important part is, that it is rendered depending on the models property "visible". The model is given to the component via parm "name".
<cc:interface>
<cc:attribute name="name" required="true"/>
</cc:interface>
<cc:implementation componentType="ch.sbi.pt.components.PMSInputText">
<h:inputText value="#{cc.attrs.name.value}" rendered="#{cc.attrs.name.visible}"/>
</cc:implementation>
In the view i have a panelGrid with 2 cells/row: the first row has a label and my cc, the second is not important. The label renders itself with the same model-property as my cc does.
<h:panelGrid columns="2">
<h:outputText value="Name" rendered="#{person.name.visible}"/>
<sbic:pmsInputText name="#{person.name}"/>
<h:outputText value="Next Label"/>
<sbic:pmsInputText name="#{something.name}"/>
</h:panelGrid>
The result (and problem) is the following, if "visible"-property returns "false":
None of the components are rendered (perfect!) BUT the cc resulting HTML leaves an empty cell (e.g. <td></td>) which results in a ugly layouted HTML-Table (offset one cell):
<table>
<tbody>
<tr>
<td></td>
<td>Next Label</td>
</tr>
....
As far as I understand this has to do with the lifecycle (jstl vs. jsf): my cc renders before the <h:outputText../> but how can i get rid of the empty cell (e.g. <td></td>)? Am i missing something here?
Thanx for your help, experts!
Marc
This is fully expected. The composite component is rendered. Only its children are not. You need to move the rendered attribute to the composite component instead.
<sbic:pmsInputText name="#{person.name}" rendered="#{person.name.visible}" />

Resources