Primefaces static and dynamic columns in datatable - jsf-2

I am using Primefaces 5.0 to create a dynamic datatable.
My DataObject has some required fields and a List of optional "tupel" (key-value pair). The optional list may vary in size. Therefore I need a dynamic mechanism to show a List of DataObject in Primefaces.DataTable.
My approach looks like:
public class DataObject {
private String staticval1;
private String staticval2;
private List<Tupel> optionalValues;
// .. getter, setter, hashCode, toString.....
}
public class Tupel{
private String id;
private String value;
}
#ManagedBean
#ViewScoped
public class TableOverviewBean {
private List<DataObject> data;
#EJB
private IMyDao myDao;
#PostConstruct
public void init() {
data = myDao.findAll();
}
public List<DataObject> getData() {
return data;
}
public void setData(List<DataObject> data) {
this.data = data;
}
}
<h:form>
<p:dataTable value="#{tableOverviewBean.data}" var="data">
<p:column headerText="static1">
<h:outputText value="#{data.staticval1}" />
</p:column>
<p:column headerText="static2">
<h:outputText value="#{data.staticval2}" />
</p:column>
<p:columns value="#{data.optionalValues}" var="opt" headerText="#{opt.id}">
<h:outputText value="#{opt.value}" />
</p:columns>
</p:dataTable>
</h:form>
But this does not work. The dynamic columns are not rendered.
How can I solve my problem?
EDIT:
Expected result:
staticval1 | staticval2 | dynamic_id1 | dynamic_id2 | ... | dynmic_idn
----------------------------------------------------------------------
static1a | static2a | dyna_value1a| dyna_value2a | ... | dyna_valu3a
static1b | static2b | dyna_value1b| dyna_value2b | ... | dyna_valu3b
static1c | static2c | dyna_value1c| dyna_value2c | ... | dyna_valu3c

It isn't possible to define columns based on row data. Imagine that row 1 has 2 columns, row 2 has 6 columns, row 3 has 1 column, etc how would you ever produce a technically valid table in HTML? Each row must have the same amount of columns.
You've 2 options, depending on whether can change the model or not:
If you can't change the model, then you need to replace that <p:columns> by a single <p:column> and loop over the #{data.optionalValues} using a nested loop with e.g. <ui:repeat> or perhaps even another <p:dataTable><p:columns>:
<p:column>
<p:dataTable value=""><!-- Empty string as value forces 1 row. -->
<p:columns value="#{data.optionalValues}" var="opt" headerText="#{opt.id}">
#{opt.value}
</p:columns>
</p:dataTable>
</p:column>
If you can change the model, then you need to let <p:columns value> point to a bean property instead of to a row property, so that it's exactly the same for every row. This works if you replace List<Tupel> optionalValues by Map<String, Tupel> optionalValues where the key is Tupel#id and add a List<String> property to the bean containing all available Tupel#id values.
<p:columns value="#{tableOverviewBean.availableTupelIds}" var="id" headerText="#{id}">
#{data.optionalValues[id].value}
</p:columns>

java:
#Named
#ViewScoped
public class LiveRangeService implements Serializable {
private List< Map<String, ColumnModel> > tableData;
private List<ColumnModel> tableHeaderNames;
public List<Map<String, ColumnModel>> getTableData() {
return tableData;
}
public List<ColumnModel> getTableHeaderNames() {
return tableHeaderNames;
}
public void PlayListMB() {
tableData = new ArrayList< Map<String, ColumnModel> >();
//Generate table header.
tableHeaderNames = new ArrayList<ColumnModel>();
for (int j = 0; j < 5; j++) {
tableHeaderNames.add(new ColumnModel("header "+j, " col:"+ String.valueOf(j+1)));
}
//Generate table data.
for (int i = 0; i < 10; i++) {
Map<String, ColumnModel> playlist = new HashMap<String, ColumnModel>();
for (int j = 0; j < 5; j++) {
playlist.put(tableHeaderNames.get(j).key,new ColumnModel(tableHeaderNames.get(j).key,"row:" + String.valueOf(i+1) +" col:"+ String.valueOf(j+1)));
}
tableData.add(playlist);
}
}
static public class ColumnModel implements Serializable {
private String key;
private String value;
public ColumnModel(String key, String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
}
And XHTML:
<h:form>
<p:dataTable id="tbl" var="result"
value="#{liveRangeService.tableData}"
rendered="#{not empty liveRangeService.tableData}"
rowIndexVar="rowIndex"
>
<f:facet name="header"> header table </f:facet>
<p:column>
<f:facet name="header">
<h:outputText value="序号" />
</f:facet>
<h:outputText value="#{rowIndex+1}" />
</p:column>
<p:columns value="#{liveRangeService.tableHeaderNames}"
var="mycolHeader" columnIndexVar="colIndex">
<f:facet name="header">
<h:outputText value="#{mycolHeader.value}" />
</f:facet>
<h:outputText value="#{result[mycolHeader.key].value}" />
<br />
</p:columns>
</p:dataTable>
</h:form>
That's a example.

Related

Rendered attribute for PrimeFaces datatable not working

I have a primeface table that shows data from an database stored in a List called notificationList based on a search from. I want the table to be displayed after the submit button is clicked however after I add the rendered attribute the table not displaying at all. Can someone tell what I'm doing wrong and how to fix it? I've tried two methods to do this.
Using rendered=#{not empty notificationSearchBean.results.notificationList} which didn't work even though the list isn't empty (I know bc I printed out the results in the console)
Creating a boolean called visible like in this post "Want to show a data table populated with data after a button click". This also isn't displaying the table regardless of whether visible is set to true or false. What's weird is that I've tried initializing visible with true and the table is still not being rendered.
This is my code for the table:
<h:panelGroup id = "table-wrapper" styleClass="searchResults">
<h:form id="result" >
<p:dataTable id="notTable" var="notifications" value="#{notificationSearchBean.results.notificationList}" row="15">
<p:column headerText="Notification No.">
<h:outputText value="#{notifications.notificationNo}"/>
</p:column>
<p:column headerText="Service">
<h:outputText value="#{notifications.srvce}"/>
</p:column>
<p:column headerText="Operation">
<h:outputText value="#{notifications.oprtn}"/>
</p:column>
<p:column headerText="Service Version">
<h:outputText value="#{notifications.srvceVrsn}"/>
</p:column>
<p:column headerText="Event Date">
<h:outputText value="#{notifications.evntDt}" >
<f:convertDateTime pattern="dd-MMM-yyyy 'at' HH:mm:ss.SSS" />
</h:outputText>
</p:column>
</p:dataTable>
</h:form>
</h:panelGroup>
And code for the submit button:
<h:panelGrid align="center" columns="2">
<p:commandButton value="Start Search" action="#{notificationSearchBean.getAllNotificationsForQuery}" update="table-wrapper"/>
</h:panelGrid>
And the NotificationSearchBean:
#ManagedBean(name = "notificationSearchBean" )
#SessionScoped
public class NotificationSearchBean implements Serializable {
private static final long serialVersionUID = 1L;
private TransactionsDao transactionsDao = (TransactionsDao)((Login)FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("login")).getTransDao();
#Inject
private SearchCriteria search;
#Inject
private ResultSet results;
#PostConstruct
public void initialize() {
//setting attributes for search form
}
//getters and setters for search
public ResultSet getResults() {
return results;
}
public void setResults(ResultSet results) {
this.results = results;
}
public String getAllNotificationsForQuery() {
List<NotificationLogT> notifications=transactionsDao.getAllNotifications(this.search);
int temp=notifications.size();
this.results.setNotificationList(notifications);
if(temp==0){
//prints out not results return message
}
return "success";
}
}
And also the ResultSet class:
public class ResultSet implements Serializable {
private List<NotificationLogT> notificationList;
private boolean visible = false;
//private Integer dataSize;
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
public List<NotificationLogT> getNotificationList() {
setVisible(true);
return notificationList;
}
public void setNotificationList(List<NotificationLogT> notificationList) {
this.notificationList = notificationList;
}
}

Primefaces ColumnToggler does'nt work with pagination

I've got a datatable along with sort, filter and columntoggler.
Firstly, when I select and unselect a column in the same page everything is fine.
As you can see, my first column has disappeared
My problem here is when I go to the next page with pagination tool and if I want to unselect a column, it displays only the column header and not their rows as you can see below :
The initial hidden column is now displayed but we've got a gap. The last column is right now empty and the first one take the value to the second column.
This is my datatable structure :
<p:dataTable id="datatable" var="mon" value="#{X.resultQuery}"
first="#{dataTableController.first}"
resizableColumns="true"
rows="20"
paginator="true"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="30,40,50"
draggableColumns="true"
paginatorPosition="bottom"
selectionMode="single" rowKey="#{mon[4]}"
>
<f:facet name="header">
<p:commandButton id="toggler" type="button" value="Hide Columns" icon="ui-icon-calculator" />
<p:columnToggler datasource="datatable" trigger="toggler">
<p:ajax event="toggle" listener="#{columnTogglerController.onToggle}" />
</p:columnToggler>
</f:facet>
This is my ColumnTogglerController :
public class ColumnTogglerController implements Serializable {
private List<Boolean> list;
/**
* Creates a new instance of ColumnTogglerController
*/
public ColumnTogglerController() {
}
public List<Boolean> getList() {
return list;
}
public void setList(List<Boolean> list) {
this.list = list;
}
#PostConstruct
public void init() {
setList(Arrays.asList(true, true, true, true, true, true, true, true, true, true, true));
}
public void onToggle(ToggleEvent e) {
list.set((Integer) e.getData(), e.getVisibility() == Visibility.VISIBLE);
}
}
Basically my program is based on this blog :
http://blog.primefaces.org/?p=3341
Thanks for you help.
I happen to encounter this recently. The blog actually works. The problem is draggableColumns="true" makes the index of columns change. So, instead of list I used 2 maps:
private final Map<String, Boolean> colVisibilityMap = new HashMap<>();
private final Map<Integer, String> colIndexMap = new HashMap<>();
During initialization, I set the colIndexMap and the colVisibilityMap (and I used the id/clientId as the key).
On column reorder, I update the colIndexMap.
And on toggle, I update the colVisibilityMap base on colIndexMap.
public Map<String, Boolean> getColVisibilityMap() {
return Collections.unmodifiableMap(colVisibilityMap);
}
private String getColumnId(String fullId) {
String[] idParts = fullId.split(":");
return idParts[idParts.length - 1];
}
#PostConstruct
public void init() {
FacesContext context = FacesContext.getCurrentInstance();
DataTable table = (DataTable) context.getViewRoot().findComponent(":form:tableid");
List<UIColumn> columns = table.getColumns();
for (int i = 0; i < columns.size(); i++) {
final String columnId = this.getColumnId(columns.get(i).getClientId());
colIndexMap.put(i, columnId);
colVisibilityMap.put(columnId, true);
});
}
public void onColumnReorder(AjaxBehaviorEvent e) {
List<UIColumn> columns = ((DataTable) e.getSource()).getColumns();
for (int i = 0; i < columns.size(); i++) {
this.colIndexMap.put(i, this.getColumnId(columns.get(i).getClientId()));
}
}
public void onToggle(ToggleEvent e) {
// If we use list here, e.getData() may not be the correct index due to column reordering.
this.colVisibilityMap.put(this.colIndexMap.get((Integer) e.getData()), e.getVisibility() == Visibility.VISIBLE);
}
Here is the code on my JSF page:
<p:dataTable id="tableid" widgetVar="tableWidgetVar" draggableColumns="true" paginator="true"
<!-- ommitted other attributes -->
>
<p:ajax event="colReorder" listener="#{bean.onColumnReorder}"/>
<f:facet name="header">
<p:commandButton id="toggler" type="button" value="Columns"/>
<p:columnToggler datasource="tableid" trigger="toggler">
<p:ajax event="toggle" listener="#{bean.onToggle}"/>
</p:columnToggler>
</f:facet>
<p:column id="col1" visible="#{bean.colVisibilityMap['col1']}">
<!-- ommitted -->
</p:column>
<p:column id="col2" visible="#{bean.colVisibilityMap['col2']}">
<!-- ommitted -->
</p:column>
<!-- and so on... -->
</p:dataTable>

operations on validated text fields in jsf

I'm Using Primefaces 3.5. I have around 10 input text fields in my .xhtml page.Few text fields are made mandatory with attribute required="true".
I have a search button that displays Data from Database in a Data Table.The functionality of my page is to insert the values into these fields by on row select() the data in the Data Table of Search Button.
The Problem here is the data is inserting into the Fields which are highlighted with the red border ie fields with validations applied.
Example:
Transport Field has no validation but it had value that has to be inserted. These type of things are happening to many of my Input Fields.
Please give me some suggestions.
.xhtml file is:
<p:inputText id="email" value="#{addcust.c.email}" required="true"
validatorMessage="Enter Valid Email">
<f:validateRegex pattern="^[_A-Za-z0-9-\+]+(\.[_A-Za-z0-9-]+)*#[A-Za-z0-9-]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})$"/></p:inputText>
<h:outputLabel value="Transport"></h:outputLabel>
<p:inputText value="#{addcust.c.transport}" </p:inputText>
<p:commandButton value="add" type="submit" update=":form,:msg" actionListener="#{addcust.onAddSelect}"</p:commandButton>
<p:commandButton value="Search" type="submit" onclick="ser.show() "></p:commandButton>
<p:dialog id="dialog11" header=" Search" widgetVar="ser" resizable="false" showEffect="fade"
hideEffect="explode" >
<p:dataTable id="dt" var="sd" value="#{addcust.al}" selection="#{addcust.c}">
<p:ajax event="rowSelect" update=":form" listener="#{addcust.onRowSelect}"
oncomplete="ser.hide()"/>
<p:column>
<f:facet name="header">
<h:outputText value="Email"/>
</f:facet>
<h:outputText value="#{sd.email}"/>
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Transport"/>
</f:facet>
<h:outputText value="#{sd.transport}"/>
</p:column>
</p:dataTable>
customerbean.java
public class customerbean {
private String email;
private String transport;
public String getTransport() {
return transport;
}
public void setTransport(String transport) {
this.transport = transport;
}
return email;
}
public void setEmail(String email) {
this.email = email;
}
addcust.java
public customerbean c = new customerbean();
public ArrayList<customerbean> al;
public void onAddSelect(){
// Inserted my values into customer table.
}
public void onSearchSelect() {
try {
st = con.createStatement();
ResultSet rs = st.executeQuery("select * from customer where cmpid=" + getCurrcompanyid() + "");
al = new ArrayList<customerbean>();
while (rs.next()) {
customerbean s = new customerbean();
s.setEmail(rs.getString(1));
s.setTransport(rs.getString(2));
}
} catch (Exception e) {
System.out.println(e);
}
}
public void onRowSelect(SelectEvent event) throws SQLException {
customerbean r = (customerbean)event.getObject();
c = r;
}
If I'm not clear enough please leave me a comment .Thanks for Reading.

NumberFormatException for input String in datatable

I have the following method in my DAO where I retrieve a list of persons :
public List<Personne> getAllUsers() {
Query query = em.createQuery("SELECT p FROM Personne p where TYPE(p) =Utilisateur");
#SuppressWarnings("unchecked")
List <Personne> personnes = query.getResultList();
return personnes;
}
I want to show the list of persons in a datatable :
<p:dataTable value="#{desacBean.users}" var="us" paginator="true" selection="# {desacBean.selectedUser}" selectionMode="single" rowKey="#{desacBean.getId(us)}}" first="1">
<p:ajax event="rowSelect" listener="#{desacBean.onUserSelect}"/>
<p:column>
<f:facet name="n">
<h:outputText value="nom" />
</f:facet>
<h:outputText value="#{us.nom}"/>
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="prenom" />
</f:facet>
<h:outputText value="#{us.prenom}"/>
</p:column>
</p:dataTable>
my BEAN :
#ManagedBean(name="desacBean")
#SessionScoped
public class DesactiveBean implements Serializable{
private static final long serialVersionUID = 1L;
private List<Personne> users = new ArrayList<Personne>();
private Personne selectedUser;
private boolean panelRendered;
UserDAO daoUser = new UserDaoImpl();
public void rowSelect(SelectEvent event){
selectedUser = (Personne)event.getObject();
System.out.println("selectedUser = "+selectedUser.getNom_ut());
this.panelRendered = true;
}
public int getId(Personne car)
{
return System.identityHashCode(car);
}
public void onUserSelect(SelectEvent event){
this.selectedUser = (Personne)event.getObject();
System.out.println("selectedUser = "+selectedUser.getNom_ut());
}
I have the following error when trying to show this dataTable :
java.lang.NumberFormatException: For input string: "prenom"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:492)
at java.lang.Integer.parseInt(Integer.java:527)
For input string: "prenom"
how can I fix it?
You'll probably encountering the same issue as the question answered here: NumberFormatException for input String

Primefaces Collector Remove not working

I am testing the primefaces collector example given in Showcase for my code
I read somewhere that its necessary to override the equals and hashcode method for that.
Even after overriding the methods , I am still getting the same error.
Kindly tell me whats wrong in my code
User.java
#ManagedBean
public class User implements Serializable{
public String name;
public String designation;
public String division;
public User(String name,String division){
setName(name);
setDivision(division);
}
public User(){
}
public String getDesignation() {
return designation;
}
public void setDesignation(String designation) {
this.designation = designation;
}
public String getDivision() {
return division;
}
public void setDivision(String userDivision) {
this.division = userDivision;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
commApprover.java
#ManagedBean
#ViewScoped
public class CommApprover implements Serializable{
private User approver = new User();
private List<User> approvers = new ArrayList<User>();
public String reinit() {
approver = new User();
return null;
}
public User getApprover() {
return approver;
}
public void setApprover(User approver) {
this.approver = approver;
}
public List<User> getApprovers() {
return approvers;
}
public void setApprovers(List<User> approvers) {
this.approvers = approvers;
}
#Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
if (approver!= null ? !approver.equals(this.approver) : this.approver != null)
return false;
return true;
}
#Override
public int hashCode()
{
int result = approver.hashCode();
return result;
}
}
index.xhtml
<p:growl id="msgs" />
<p:panel header="Approval Route ">
<h:panelGrid columns="3" id="grid">
<h:outputText value="Name*" />
<h:outputText value="Designation*" />
<h:outputText value="Division*" />
<p:inputText id="app_name" value="#{commApprover.approver.name}" required="true"/>
<p:inputText id="app_designation" value="#{commApprover.approver.designation}" required="true"/>
<p:inputText id="app_division" required="true" value="# {commApprover.approver.division}" />
<p:commandButton id="btn_add" value="Add" update="approvers #parent" action="#{commApprover.reinit}" >
<p:collector value="#{commApprover.approver}" addTo="#{commApprover.approvers}" />
</p:commandButton>
</h:panelGrid>
</p:panel>
<p:outputPanel id="approvers">
<p:dataTable id="approversTable" value="#{commApprover.approvers}" var="approver">
<p:column>
<f:facet name="header">
<h:outputText value="Name" />
</f:facet>
<h:outputText value="#{approver.name}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Designation" />
</f:facet>
<h:outputText value="#{approver.designation}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Division" />
</f:facet>
<h:outputText value="#{approver.division}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Operation" />
</f:facet>
<p:commandLink ajax="true" value="Remove" update=":appform:approvers" process=":appform:approvers">
<p:collector value="#{approver}" removeFrom="#{commApprover.approvers}" />
</p:commandLink>
</p:column>
</p:dataTable>
</p:outputPanel>
</h:form>
This post is old but I ran into the same problem and after some debuging I found out that this problem is related to incorrectly implemented hashCode and equals, when using converters or p:collector you have to implement hashCode and equals to compare all fields in your entity otherwise it fails even if the item you are trying to remove is the correct one. Also it is recomended that you override those properties in your Pojo not in you ManagedBean. This post helped me to understand the problem https://blog.art-of-coding.eu/jsf-converters-and-equals-hashcode/

Resources