datatable with lazyloading and rowexpansion gives wrong object when opening expansion - primefaces

I'm using a normal datatable with lazyloading and rowexpansion with a nested table and I have problems by opening the rowexpansion after lazyloading. ScrollRows is setted to 150.
<ui:composition template="/ressources/basic.xhtml" xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui">
<ui:define name="title">#{label['template.tab1']}</ui:define>
<ui:define name="content">
<h:form id="crateTbl">
<p:dataTable rowExpandMode="single" id="cTbl" var="crate" value="#{cratesView.lazyModel}" selectionMode="single"
filteredValue="#{cratesView.filteredCrates}" selection="#{cratesView.selectedCrate}"
lazy="true" liveScroll="true" scrollRows="150"
widgetVar="cratesTbl" rowKey="#{crate.id}" scrollable="true" scrollHeight="550">
<p:column style="width:16px" exportable="false">
<p:rowToggler />
</p:column>
<p:column headerText="#{label['crate.col.grp']}" filterStyle="width:60px;" filterBy="#{crate.grp}" filterMatchMode="contains" width="60">
<h:outputText value="#{crate.grp}"/>
</p:column>
...additional columns of crate.
<p:rowExpansion >
<p:panelGrid columnClasses="label,value" >
<div class="remark-label"><b>#{label['crateview.toggle.remark']}</b>: <h:outputLabel value="#{crate.remark}"/></div>
<p:dataTable id='bTbl' var="bottle" value="#{cratesView.getBottles2Crate(crate)}"
widgetVar="bottleTbl" rowKey="#{bottle.id}" scrollable="true" scrollHeight="300">
<p:column headerText="#{label['bottle.col.grp']}" width="50">
<h:outputText value="#{bottle.grp}"/>
</p:column>
...additional columns of bottle
</p:dataTable>
</p:column>
</p:row>
</p:panelGrid>
</p:rowExpansion>
</p:dataTable>
</h:form>
</ui:define>
and Bean:
#ManagedBean(name = "cratesView")
#ViewScoped
public class CrateView implements Serializable {
//object definitions
#PostConstruct
public void init() {
//init some objects
lazyModel = new LazyCrateDatamodel(cratesList);
}
public LazyDataModel<Crate> getLazyModel() {
return lazyModel;
}
public void setLazyModel(LazyCrateDatamodel lazyModel){
this.lazyModel = lazyModel;
}
public void setSelectedCrate(final Crate c){
this.selectedCrate = c;
}
public Crate getSelectedCrate() {
return this.selectedCrate;
}
public List<Crate> getFilteredCrates() {
return filteredCrates;
}
public void setFilteredCrates(List<Crate> filteredCrates) {
this.filteredCrates = filteredCrates;
}
public List<Bottle> getBottles2Crate(final Crate c)
{
int grp = c.getGrp(); //
return gProvider.getBottlesByCrate(calculated.getGrp(), 0);
}
}
Everything runs fine on the firstpage, opening the expansion shows correct data in the table. After loading the next 150 rows and scrolling back to e.g. the first row and opening the expansion the data of a wrong crate is loaded. cratesView.getBottles2Crate(crate) is called with a crate-object shifted by n*150(n - numbers of loadings). The object of the rowtoggling-event is not the same of the datamodel. On the other side setSelectedCrate gets the right object.
Do I have something misconfigurated or is there a hint in the docs using rowexpansion and lazyloading...
Thanks for some hints.
Edit: Correct some syntax.

Sorry for the missing information:
Mojarra JSF Implementation 2.3.0 (20170310-1214)
Primeface 6.2
I tested it parallel with a minimal version:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Lazy Test</title>
<link rel="icon" href="imgs/favicon.ico" type="image/x-icon" />
</h:head>
<body>
<h:form id="crateTbl">
<p:dataTable rowExpandMode="single" id="cTbl" var="crate" value="#{lazyView.model}" selectionMode="single" selection="#{lazyView.selectedCrate}"
lazy="true" liveScroll="true" scrollRows="150"
widgetVar="cratesTbl" rowKey="#{crate.id}" scrollable="true" scrollHeight="550">
<p:column style="width:16px" exportable="false">
<p:rowToggler />
</p:column>
<p:column headerText="Kistengrp" width="60">
<h:outputText value="#{crate.grp}"/>
</p:column>
<p:column headerText="Kistennamen" width="250">
<h:outputText value="#{crate.name}"/>
</p:column>
<p:column headerText="Flaschengrp" width="100">
<h:outputText value="#{crate.bgrp}"/>
</p:column>
<p:rowExpansion >
<p:panelGrid columnClasses="label,value" >
<p:dataTable id='bTbl' var="bottle" value="#{lazyView.getBottlesByCrate(crate)}" widgetVar="bottleTbl" rowKey="#{bottle.id}" scrollable="true" scrollHeight="300">
<p:column headerText="Gruppe" width="50">
<h:outputText value="#{bottle.grp}"/>
</p:column>
<p:column headerText="Name" width="250">
<h:outputText value="#{bottle.name}"/>
</p:column>
<p:column headerText="Id" width="100">
<h:outputText value="#{bottle.id}"/>
</p:column>
</p:dataTable>
</p:panelGrid>
</p:rowExpansion>
</p:dataTable>
</h:form>
</body>
</html>
Classes:
Testdata provider:
package de.test;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
#ManagedBean(name = "testservice")
#ApplicationScoped
public class AssortmentProvider {
private final static String[] NAMES = {"Uerige","Koelsch","Wasser","Saft","Limo","Cola","Kupfer","Messing"};
private final static int[] BGRPS = {1,12,15,20,24,25,26,30,100,112,155,200,201,242,250};
private final static int[] CGRPS = {1000,1020,1050,2000,2400,2500,2600,3000,1006,1120,1550,2050,2010,2420,2500};
private List<Crate> crates;
private List<Bottle> bottles;
#PostConstruct
public void init() {
this.createBottles();
this.createCrates();
}
public List<Crate> getCrates() { return crates; }
public List<Bottle> getBottles() { return bottles; }
public List createCrates() {
crates = new ArrayList<>();
for(int i=0;i<500;i++) {
int n = (int) (Math.random() * 8);
int g = (int) (Math.random() * 15);
int b = (int) (Math.random() * 15);
Crate c = new Crate(NAMES[n], i, CGRPS[g]);
c.setBgrp(BGRPS[b]);
crates.add(c);
}
return crates;
}
public List createBottles() {
bottles = new ArrayList<>();
for(int i=0;i<500;i++) {
int n = (int) (Math.random() * 8);
int b = (int) (Math.random() * 15);
Bottle btl = new Bottle("B_" + NAMES[n], i, BGRPS[b]);
bottles.add(btl);
}
return bottles;
}
}
Entities Crate:
package de.test;
public class Crate extends Entity {
private int bgrp;
public Crate(String name, int id, int cgrp) { super(name,id,cgrp); }
public int getBgrp() { return bgrp; }
public void setBgrp(int bgrp) { this.bgrp = bgrp; }
#Override
public String toString() { return "Crate{" + "name=" + name + ", id=" + id + ", grp=" + grp + ", bgrp=" + bgrp +'}'; }
}
next Bottle:
package de.test;
public class Bottle extends Entity {
public Bottle(String name, int id, int grp) { super(name,id,grp); }
#Override
public String toString() { return "Bottle{" + "name=" + name + ", id=" + id + ", grp=" + grp + '}'; }
}
next Entity:
package de.test;
public class Entity {
protected String name;
protected int id;
protected int grp;
public Entity(String name, int id, int grp) {
this.name = name;
this.id = id;
this.grp = grp;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public int getGrp() { return grp; }
public void setGrp(int grp) { this.grp = grp; }
}
next LazyView:
package de.test;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
#ManagedBean(name = "lazyView")
#ViewScoped
public class LazyView implements Serializable {
#ManagedProperty("#{testservice}")
AssortmentProvider service;
List<Crate> crateList;
Crate selectedCrate;
LazyCrateModel model;
#PostConstruct
public void init() {
crateList = this.service.createCrates();
model = new LazyCrateModel(crateList);
}
public void setService(AssortmentProvider service) { this.service = service; }
public Crate getSelectedCrate() { return selectedCrate; }
public void setSelectedCrate(Crate selectedCrate) { this.selectedCrate = selectedCrate; }
public List<Crate> getCrateList() { return crateList; }
public void setCrateList(List<Crate> crateList) { this.crateList = crateList; }
public LazyCrateModel getModel() { return model; }
public List<Bottle> getBottlesByCrate(final Crate c) {
System.out.println(c);
List<Bottle> l = new ArrayList<>();
for(Bottle b : service.getBottles())
{
if( b.getGrp() == c.getBgrp())
l.add(b);
}
return l;
}
}
next LazyDatamodel:
package de.test;
import java.util.List;
import java.util.Map;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortOrder;
public class LazyCrateModel extends LazyDataModel<Crate> {
private final List<Crate> list;
public LazyCrateModel(List<Crate> list) { this.list = list; }
#Override
public Integer getRowKey(Crate object) { return object.getId(); }
#Override
public List<Crate> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
this.setRowCount(list.size());
if(first + pageSize > list.size()) {
pageSize = list.size() - first;
}
List<Crate> sub = list.subList(first, first + pageSize);
return sub;
}
#Override
public Crate getRowData(String str) {
int idx = Integer.parseInt(str);
for(Crate c : list) {
if(c.getId() == idx)
return c;
}
return null;
}
}
It's the same behavior: After one loading scrolling to the beginning, the given crate is the 150 shifted crate, not crate[0].
Hope someone can verify this behavior.

Related

PrimeFaces DataTable not displaying anything, as backing bean's methods are not called at all

I have a problem similar to the ones described here:
primefaces datatable not displaying anything
PrimeFaces DataTable "No records found" when there are records
my PrimeFaces datatable does not show any results, altough there are records in the database. Moreover: it seems that NO JAVA method is called when I request the page from the browser - at least the init() method of the backing bean seems not to be called at all
Where can the problem be? I would appreciate any help!
Thank you!
My template:
<!DOCTYPE html>
<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:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
<meta charset="UTF-8"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Bibliothek - Customers </title>
</h:head>
<h:body>
<h:form id="customersform">
<p:growl id="growl" life="2000" />
<p:panel header="All customers in the application" />
<p:dataTable id="customersTable" var="customer"
value="#{kundenBean.dataModel}" paginator="true" rows="10"
paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
resizableColumns="true" rowsPerPageTemplate="5,10,15"
selection="#{kundenBean.selektierterKunde}" selectionMode="single"
rowKey="#{customer.id}" lazy="true">
<p:column headerText="Customer's Name" style="width:332px;text-align:center"
sortBy="#{customer.vorname}" filterBy="#{customer.vorname}">
<h:outputText value="#{customer.vorname}" />
</p:column>
<p:column headerText="Customer's Address" sortBy="#{customer.adresse}"
filterBy="#{customer.adresse}">
<h:outputText value="#{customer.adresse}" />
</p:column>
</p:dataTable>
</h:form>
</h:body>
</html>
The Backing Bean:
#Named
#ViewScoped
public class KundenBean {
private Logger logger = Logger.getLogger(KundenBean.class.getName());
public static final String SELECTED_CUSTOMER = "selectedCustomer";
#Inject
private KundeDBService kundenDBService;
private LazyKundeDataModel dataModel;
private Kunde selektierterKunde;
private int selectedCustId;
#PostConstruct
private void init() {
this.dataModel = new LazyKundeDataModel(kundenDBService);
}
public LazyKundeDataModel getDataModel() {
return dataModel;
}
public void setDataModel(LazyKundeDataModel dataModel) {
this.dataModel = dataModel;
}
public Kunde getSelektierterKunde() {
return selektierterKunde;
}
public int getSelectedCustId() {
return selectedCustId;
}
public void setSelektierterKunde(Kunde selektierterKunde) {
this.selektierterKunde = selektierterKunde;
}
public void onRowSelect(SelectEvent event) {
selectedCustId = ((Kunde) event.getObject()).getId();
}
public void onRowDblClick(final SelectEvent event) {
selectedCustId = ((Kunde) event.getObject()).getId();
try {
ExternalContext extCtx = FacesContext.getCurrentInstance()
.getExternalContext();
extCtx.getFlash().put(SELECTED_CUSTOMER,((Kunde) event.getObject()));
FacesContext.getCurrentInstance().getExternalContext().redirect("rents.xhtml?custId=" +selectedCustId);
} catch (IOException e) {
e.printStackTrace();
logger.error(e.getMessage(), e);
}
}
}
The Data Model:
public class LazyKundeDataModel extends LazyDataModel<Kunde> {
private static final long serialVersionUID = 1L;
private KundeDBService kundeDBService;
public LazyKundeDataModel(KundeDBService kundeDBService) {
this.kundeDBService = kundeDBService;
}
#Override
public Kunde getRowData(String rowKey) {
return kundeDBService.getKundeById(Integer.valueOf(rowKey));
}
#Override
public Object getRowKey(Kunde kunde) {
return kunde.getId();
}
#Override
public List<Kunde> load(int first, int pageSize, String sortField, SortOrder sortOrder,
Map<String, Object> filters) {
List result = this.kundeDBService.load(first, pageSize, sortField, sortOrder, filters);
// rowCount
this.setRowCount(result.size());
this.setPageSize(pageSize);
return result;
}
}
The DB Service:
#Stateless
public class KundeDBService {
#PersistenceContext
private EntityManager em;
public static final String JOINING_OR = " OR ";
public static final String JOINING_AND = " AND ";
public static final String CONDITION_WHERE = " WHERE ";
private static Logger logger = Logger.getLogger(KundeDBService.class.getName());
public List<? extends Kunde> load(int first, int pageSize, String sortField, SortOrder sortOrder,
Map<String, Object> filters) {
List<? extends Kunde> result = new ArrayList<Kunde>();
String selectQUERY = " select k from Kunde k ";
if (filters.size() > 0) {
selectQUERY += addFiltersToQuery(filters);
}
if (sortField != null) {
selectQUERY += " order by k." + sortField;
if (sortOrder != null) {
selectQUERY += " " + (sortOrder);
}
}else { // sortField == null, default sort by customer's name
selectQUERY += " order by k.vorname asc";
}
Query emQuery = em.createQuery(selectQUERY);
emQuery.setFirstResult(first);
emQuery.setMaxResults(pageSize);
result = (List<Kunde>) emQuery.getResultList();
return result;
}
private String addFiltersToQuery(Map<String, Object> filters) {
if (filters.size() == 0)
return StringUtils.EMPTY;
StringBuilder whereCondition = new StringBuilder(CONDITION_WHERE);
int pseudoCounter = 0;
for (Entry<String, Object> entry : filters.entrySet()) {
whereCondition.append("k." + entry.getKey() + " LIKE :" + "x" + (++pseudoCounter));
whereCondition.append(JOINING_AND);
}
if (whereCondition.length() > CONDITION_WHERE.length()) {
whereCondition.delete(whereCondition.length() - JOINING_AND.length(), whereCondition.length());
}
return whereCondition.toString();
}
public Kunde getKundeById(int id) {
return em.find(Kunde.class, Integer.valueOf(id));
}
}
I solved the problem by replacing the annotation #Named by the annotation javax.faces.bean.ManagedBean on the KundenBean class. I am not sure what exactly the problem was, but I suppose that it has something to do with the problem outlined here
JSF View Scoped Bean Reconstructed Multiple Times
So, now the changed and working KundenBean class looks like this:
#ManagedBean (name = "kundenBean")
#ViewScoped
public class KundenBean {
//rest of the lines unchanged

Open details of a single row in a datatable in a new page

I have a datatable from database and I would like details of one of the rows appear in a new table when I click on the "OPEN" button as in the screenshot below.
When I click on the OPEN button I get "No records found " as in the next screenshot below
Here is part of the index.xhtml
//
APP WEB
<p:ajax event="rowEdit" listener="#{transaction.onRowEdit}" update=":form1:messages" />
<p:ajax event="rowEditCancel" listener="#{transaction.onRowCancel}" update=":form1:messages" />
<p:column headerText="Reference">
<p:commandLink value="#{c.reference}" action="/faces/global/SingleTx.xhtml" target="_blank" >
<f:setPropertyActionListener target="#{transaction.showSelectedTx(reference)}" value="#{c}" />
</p:commandLink>
</p:column>
<p:column headerText="Rartner">
#{c.pname}
</p:column>
<p:column headerText="Status">
#{c.fk_status}
</p:column>
<p:column headerText="Sender">
#{c.sendername}
</p:column>
<p:column headerText="Beneficiary">
#{c.beneficiaryname}
</p:column>
<p:column headerText="Amounts">
#{c.beneficiary_currency} #{c.beneficiary_amount}
</p:column>
<p:column headerText="Action">
<p:commandButton style="float:right" value="Print" >
<p:confirm header="#{cd.reference}" message="Are you sure?" icon="ui-icon-alert" />
<p:button value="Open" href="/faces/global/SingleTx.xhtml" target="_self" />
</p:commandButton>
</p:column>
<p:column style="width:32px">
<p:rowEditor />
</p:column>
</p:dataTable>
<p:dialog modal="true" width="800px" height="400px" widgetVar="singletx"
id="dialog">
Name :#{transaction.showSelectedTx(reference)}
</p:dialog>
</h:form>
Here is the backing bean:
package com.mycompany.data;
/**
*
* #author bryan
*/
import conn.DBConnector;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean(name = "transaction")
#SessionScoped
public class TransactionBean implements Serializable {
//added
private static final long serialVersionUID = 1L;
public String reference;
public String fk_status;
public String sendername;
public String beneficiaryname;
public String beneficiary_currency;
public double beneficiary_amount;
public String pname;
Transaction user;
public String getReference() {
return reference;
}
public void setReference(String reference) {
this.reference = reference;
}
public String getFk_status() {
return fk_status;
}
public void setFk_status(String fk_status) {
this.fk_status = fk_status;
}
public String getSendername() {
return sendername;
}
public void setSendername(String sendername) {
this.sendername = sendername;
}
public String getBeneficiaryname() {
return beneficiaryname;
}
public void setBeneficiaryname(String beneficiaryname) {
this.beneficiaryname = beneficiaryname;
}
public String getBeneficiary_currency() {
return beneficiary_currency;
}
public void setBeneficiary_currency(String beneficiary_currency) {
this.beneficiary_currency = beneficiary_currency;
}
public double getBeneficiary_amount() {
return beneficiary_amount;
}
public void setBeneficiary_amount(double beneficiary_amount) {
this.beneficiary_amount = beneficiary_amount;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
//resource injection
#Resource(name = "jdbc/primefaces")
//connect to DB and get customer list
public List<Transaction> getTransactionList() throws SQLException, ClassNotFoundException {
Connection con = null;
con = DBConnector.getDBConnection();
if (con == null) {
throw new SQLException("Can't get database connection");
}
PreparedStatement ps
= con.prepareStatement(
"select tx.reference,p.pname,ts.name, tx.sendername, tx.beneficiaryname, tx.beneficiary_currency,tx.beneficiary_amount from transaction_stage tx join transaction_status ts on tx.fk_status=ts.id join partner p on tx.fk_partner=p.id");
//get customer data from database
ResultSet result = ps.executeQuery();
List<Transaction> list = new ArrayList<Transaction>();
while (result.next()) {
Transaction cust = new Transaction();
cust.setReference(result.getString("reference"));
cust.setFk_status(result.getString("name"));
cust.setSendername(result.getString("sendername"));
cust.setBeneficiaryname(result.getString("beneficiaryname"));
cust.setBeneficiary_currency(result.getString("beneficiary_currency"));
cust.setBeneficiary_amount(result.getDouble("beneficiary_amount"));
cust.setPname(result.getString("pname"));
//store all data into a List
list.add(cust);
}
return list;
//added
}
//view single transaction
private List<Transaction> selectSingleTx;
public Transaction getUser() {
return user;
}
public void setUser(Transaction user) {
this.user = user;
}
public List<Transaction> getSelectSingleTx() {
return selectSingleTx;
}
public void setSelectSingleTx(List<Transaction> selectSingleTx) {
this.selectSingleTx = selectSingleTx;
}
public void showSelectedTx(String reference){
Connection con=DBConnector.getDBConnection();
if(con==null){
System.out.println("No db connection");
}
String ref=getReference();
try {
String q="select tx.reference,p.pname,ts.name, tx.sendername, tx.beneficiaryname, tx.beneficiary_currency,tx.beneficiary_amount from transaction_stage tx join transaction_status ts on tx.fk_status=ts.id join partner p on tx.fk_partner=p.id where tx.reference="+ref+"";
PreparedStatement ps=null;
ResultSet rs=null;
ps.setString(1, reference);
rs=ps.executeQuery();
display(rs);
} catch (Exception e) {
}
}
public void selectTx(String reference){
showSelectedTx(reference);
}
// to be implemented later
private static void display(ResultSet myRs) throws SQLException {
while (myRs.next()) {
String sendername = myRs.getString("sendername");
String beneficiaryname = myRs.getString("beneficiaryname");
//double salary = myRs.getDouble("salary");
String department = myRs.getString("department");
System.out.printf("%s, %s \n", sendername, beneficiaryname);
}
}
}
//
As per the Reference link, you need to include the value of c.reference in the link
value="#{c.reference}"
See JSF ViewParam from CommandButton
or
How to pass a parameter along with h:commandButton

Prime faces 5.0: custom filter in data table ignored

I'm trying to have a selectonemenu as filter option in a data table
I've done several tests, with no success
Now I'm trying to create a sample custom filter, with selectOneButton, with static fields, trying to simplify, but again it doesn't work
<p:column filterBy="#{sController.getStatus(se)}" headerText="Stato"
style="text-align:center;" sortBy="#{sController.getStatus(se)}"
filterMatchMode="exact"
>
<f:facet name="filter">
<p:selectOneButton onchange="PF('sDataTableWV').filter()">
<f:converter converterId="javax.faces.Boolean" />
<f:selectItem itemLabel="All" itemValue="" />
<f:selectItem itemLabel="Sold" itemValue="true" />
<f:selectItem itemLabel="Sale" itemValue="false" />
</p:selectOneButton>
</f:facet>
<img src="#{resource[sController.getStatus(se)]}" />
</p:column>
The facet is completely ignored, I see the usual input field instead
-------------- EDIT ------------------
As per request, I prepared a new page taking the source code of the showcase
here is the XHTML page
<?xml version='1.0' encoding='UTF-8' ?>
<!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:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Pagina di test</title>
</h:head>
<body>
<h3>Pagina di test</h3>
<h:form>
<p:dataTable var="car" value="#{dtFilterView.cars}" widgetVar="carsTable"
emptyMessage="No cars found with given criteria" filteredValue="#{dtFilterView.filteredCars}">
<f:facet name="header">
<p:outputPanel>
<h:outputText value="Search all fields:" />
<p:inputText id="globalFilter" onkeyup="PF('carsTable').filter()" style="width:150px" placeholder="Enter keyword"/>
</p:outputPanel>
</f:facet>
<p:column filterBy="#{car.id}" headerText="Id" footerText="contains" filterMatchMode="contains">
<h:outputText value="#{car.id}" />
</p:column>
<p:column filterBy="#{car.year}" headerText="Year" footerText="lte" filterMatchMode="lte">
<f:facet name="filter">
<p:spinner onchange="PF('carsTable').filter()" styleClass="year-spinner">
<f:converter converterId="javax.faces.Integer" />
</p:spinner>
</f:facet>
<h:outputText value="#{car.year}" />
</p:column>
<p:column filterBy="#{car.brand}" headerText="Brand" footerText="exact" filterMatchMode="exact">
<f:facet name="filter">
<p:selectOneMenu onchange="PF('carsTable').filter()" >
<f:selectItem itemLabel="Select One" itemValue="#{null}" noSelectionOption="true" />
<f:selectItems value="#{dtFilterView.brands}" />
</p:selectOneMenu>
</f:facet>
<h:outputText value="#{car.brand}" />
</p:column>
<p:column filterBy="#{car.color}" headerText="Color" footerText="in" filterMatchMode="in">
<f:facet name="filter">
<p:selectCheckboxMenu label="Colors" onchange="PF('carsTable').filter()" panelStyle="width:125px" scrollHeight="150">
<f:selectItems value="#{dtFilterView.colors}" />
</p:selectCheckboxMenu>
</f:facet>
<h:outputText value="#{car.color}" />
</p:column>
<p:column filterBy="#{car.sold}" headerText="Status" footerText="equals" filterMatchMode="equals">
<f:facet name="filter">
<p:selectOneButton onchange="PF('carsTable').filter()">
<f:converter converterId="javax.faces.Boolean" />
<f:selectItem itemLabel="All" itemValue="" />
<f:selectItem itemLabel="Sold" itemValue="true" />
<f:selectItem itemLabel="Sale" itemValue="false" />
</p:selectOneButton>
</f:facet>
<h:outputText value="#{car.sold ? 'Sold': 'Sale'}" />
</p:column>
<p:column filterBy="#{car.price}" headerText="Price" footerText="custom (min)" filterFunction="#{dtFilterView.filterByPrice}">
<h:outputText value="#{car.price}">
<f:convertNumber currencySymbol="$" type="currency"/>
</h:outputText>
</p:column>
</p:dataTable>
</h:form>
</body>
</html>
here the Car.java
package controllers.test;
import java.io.Serializable;
public class Car implements Serializable {
public String id;
public String brand;
public int year;
public String color;
public int price;
public boolean sold;
public Car() {}
public Car(String id, String brand, int year, String color) {
this.id = id;
this.brand = brand;
this.year = year;
this.color = color;
}
public Car(String id, String brand, int year, String color, int price, boolean sold) {
this.id = id;
this.brand = brand;
this.year = year;
this.color = color;
this.price = price;
this.sold = sold;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public boolean isSold() {
return sold;
}
public void setSold(boolean sold) {
this.sold = sold;
}
#Override
public int hashCode() {
int hash = 7;
hash = 59 * hash + (this.id != null ? this.id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Car other = (Car) obj;
if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) {
return false;
}
return true;
}
}
then CarService.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
#ManagedBean(name = "carService")
#ApplicationScoped
public class CarService {
private final static String[] colors;
private final static String[] brands;
static {
colors = new String[10];
colors[0] = "Black";
colors[1] = "White";
colors[2] = "Green";
colors[3] = "Red";
colors[4] = "Blue";
colors[5] = "Orange";
colors[6] = "Silver";
colors[7] = "Yellow";
colors[8] = "Brown";
colors[9] = "Maroon";
brands = new String[10];
brands[0] = "BMW";
brands[1] = "Mercedes";
brands[2] = "Volvo";
brands[3] = "Audi";
brands[4] = "Renault";
brands[5] = "Fiat";
brands[6] = "Volkswagen";
brands[7] = "Honda";
brands[8] = "Jaguar";
brands[9] = "Ford";
}
public List<Car> createCars(int size) {
List<Car> list = new ArrayList<Car>();
for(int i = 0 ; i < size ; i++) {
list.add(new Car(getRandomId(), getRandomBrand(), getRandomYear(), getRandomColor(), getRandomPrice(), getRandomSoldState()));
}
return list;
}
private String getRandomId() {
return UUID.randomUUID().toString().substring(0, 8);
}
private int getRandomYear() {
return (int) (Math.random() * 50 + 1960);
}
private String getRandomColor() {
return colors[(int) (Math.random() * 10)];
}
private String getRandomBrand() {
return brands[(int) (Math.random() * 10)];
}
public int getRandomPrice() {
return (int) (Math.random() * 100000);
}
public boolean getRandomSoldState() {
return (Math.random() > 0.5) ? true: false;
}
public List<String> getColors() {
return Arrays.asList(colors);
}
public List<String> getBrands() {
return Arrays.asList(brands);
}
}
and last FilterView.java
import java.io.Serializable;
import java.util.List;
import java.util.Locale;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
#ManagedBean(name="dtFilterView")
#ViewScoped
public class FilterView implements Serializable {
private List<Car> cars;
private List<Car> filteredCars;
#ManagedProperty("#{carService}")
private CarService service;
#PostConstruct
public void init() {
cars = service.createCars(10);
}
public boolean filterByPrice(Object value, Object filter, Locale locale) {
String filterText = (filter == null) ? null : filter.toString().trim();
if(filterText == null||filterText.equals("")) {
return true;
}
if(value == null) {
return false;
}
return ((Comparable) value).compareTo(Integer.valueOf(filterText)) > 0;
}
public List<String> getBrands() {
return service.getBrands();
}
public List<String> getColors() {
return service.getColors();
}
public List<Car> getCars() {
return cars;
}
public List<Car> getFilteredCars() {
return filteredCars;
}
public void setFilteredCars(List<Car> filteredCars) {
this.filteredCars = filteredCars;
}
public void setService(CarService service) {
this.service = service;
}
}
The result is exactly the same, the filter are input field
I'm on glassfish 3.2
Sorry, I have my development environment with 5.0, but on production was 3.5
changing the library all worked

On Primefaces datatable lazy loading complete update backing bean

I want to update backing bean after the primefaces datatable lazy loading is complete. I see that the API has a onSuccess & onComplete method for calling clientside code. But I would like to update backing bean based on the default selection. I have registered the "page" event with my datatable
<p:ajax event="page" update="" onstart="PF('loadingDialog').show()" onsuccess="PF('loadingDialog').hide()" listener=""/>
I could have used the listener but the problem is listener is invoked even before the server side loading method is complete.
RemoteCommand provides a simple way to execute backing bean methods with javascript.
The example is shown below.
xhtml
<h:form id="form">
<p:remoteCommand name="rc" update="msgs"
actionListener="#{remoteCommandView.execute('Wittakarn')}" />
<p:growl id="msgs" showDetail="true" />
<p:dataTable var="car" value="#{dtLazyView.lazyModel}"
paginator="true" rows="10"
paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink}
{PreviousPageLink}
{CurrentPageReport}
{NextPageLink}
{LastPageLink}"
rowsPerPageTemplate="5,10,15"
selectionMode="single"
selection="#{dtLazyView.selectedCar}"
id="carTable"
lazy="true">
<p:ajax event="rowSelect"
listener="#{dtLazyView.onRowSelect}"
update=":form:carDetail"
oncomplete="PF('carDialog').show()" />
<p:ajax event="page"
update=":form:carDetail"
oncomplete="rc()" />
<p:column headerText="Id"
sortBy="#{car.id}"
filterBy="#{car.id}">
<h:outputText value="#{car.id}" />
</p:column>
<p:column headerText="Year"
sortBy="#{car.year}"
filterBy="#{car.year}">
<h:outputText value="#{car.year}" />
</p:column>
<p:column headerText="Brand"
sortBy="#{car.brand}"
filterBy="#{car.brand}">
<h:outputText value="#{car.brand}" />
</p:column>
<p:column headerText="Color"
sortBy="#{car.color}"
filterBy="#{car.color}">
<h:outputText value="#{car.color}" />
</p:column>
</p:dataTable>
<p:dialog header="Car Detail"
widgetVar="carDialog"
modal="true" showEffect="fade"
hideEffect="fade"
resizable="false">
<p:outputPanel id="carDetail"
style="text-align:center;">
<p:panelGrid columns="2"
rendered="#{not empty dtLazyView.selectedCar}"
columnClasses="label,value">
<f:facet name="header">
<p:graphicImage
name="demo/images/car/#{dtLazyView.selectedCar.brand}-big.gif"/>
</f:facet>
<h:outputText value="Id:" />
<h:outputText value="#{dtLazyView.selectedCar.id}" />
<h:outputText value="Year" />
<h:outputText value="#{dtLazyView.selectedCar.year}" />
<h:outputText value="Color:" />
<h:outputText value="#{dtLazyView.selectedCar.color}"
style="color:#{dtLazyView.selectedCar.color}"/>
<h:outputText value="Price:" />
<h:outputText value="#{dtLazyView.selectedCar.price}">
<f:convertNumber type="currency" currencySymbol="$" />
</h:outputText>
</p:panelGrid>
</p:outputPanel>
</p:dialog>
</h:form>
managedbean
#ManagedBean
public class RemoteCommandView {
public void execute() {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Executed", "Using RemoteCommand."));
}
public void execute(String detail) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, detail, "Using RemoteCommand."));
}
}
#ManagedBean(name="dtLazyView")
#ViewScoped
public class LazyView implements Serializable {
private LazyDataModel<Car> lazyModel;
private Car selectedCar;
#ManagedProperty("#{carService}")
private CarService service;
#PostConstruct
public void init() {
lazyModel = new LazyCarDataModel(service.createCars(200));
}
public LazyDataModel<Car> getLazyModel() {
return lazyModel;
}
public Car getSelectedCar() {
return selectedCar;
}
public void setSelectedCar(Car selectedCar) {
this.selectedCar = selectedCar;
}
public void setService(CarService service) {
this.service = service;
}
public void onRowSelect(SelectEvent event) {
FacesMessage msg = new FacesMessage("Car Selected", ((Car) event.getObject()).getId());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}
model
public class Car implements Serializable {
public String id;
public String brand;
public int year;
public String color;
public int price;
public boolean sold;
public Car() {}
public Car(String id, String brand, int year, String color) {
this.id = id;
this.brand = brand;
this.year = year;
this.color = color;
}
public Car(String id, String brand, int year, String color, int price, boolean sold) {
this.id = id;
this.brand = brand;
this.year = year;
this.color = color;
this.price = price;
this.sold = sold;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public boolean isSold() {
return sold;
}
public void setSold(boolean sold) {
this.sold = sold;
}
#Override
public int hashCode() {
int hash = 7;
hash = 59 * hash + (this.id != null ? this.id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Car other = (Car) obj;
if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) {
return false;
}
return true;
}
}
carService
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import org.primefaces.showcase.domain.Car;
#ManagedBean(name = "carService")
#ApplicationScoped
public class CarService {
private final static String[] colors;
private final static String[] brands;
static {
colors = new String[10];
colors[0] = "Black";
colors[1] = "White";
colors[2] = "Green";
colors[3] = "Red";
colors[4] = "Blue";
colors[5] = "Orange";
colors[6] = "Silver";
colors[7] = "Yellow";
colors[8] = "Brown";
colors[9] = "Maroon";
brands = new String[10];
brands[0] = "BMW";
brands[1] = "Mercedes";
brands[2] = "Volvo";
brands[3] = "Audi";
brands[4] = "Renault";
brands[5] = "Fiat";
brands[6] = "Volkswagen";
brands[7] = "Honda";
brands[8] = "Jaguar";
brands[9] = "Ford";
}
public List<Car> createCars(int size) {
List<Car> list = new ArrayList<Car>();
for(int i = 0 ; i < size ; i++) {
list.add(new Car(getRandomId(), getRandomBrand(), getRandomYear(), getRandomColor(), getRandomPrice(), getRandomSoldState()));
}
return list;
}
private String getRandomId() {
return UUID.randomUUID().toString().substring(0, 8);
}
private int getRandomYear() {
return (int) (Math.random() * 50 + 1960);
}
private String getRandomColor() {
return colors[(int) (Math.random() * 10)];
}
private String getRandomBrand() {
return brands[(int) (Math.random() * 10)];
}
private int getRandomPrice() {
return (int) (Math.random() * 100000);
}
private boolean getRandomSoldState() {
return (Math.random() > 0.5) ? true: false;
}
public List<String> getColors() {
return Arrays.asList(colors);
}
public List<String> getBrands() {
return Arrays.asList(brands);
}
}
You can see more detail: RemoteCommand
Since I prefer using vanilla JSF, I would do the following
put this above your table
<h:commandButton id="call-me-after-page"
style="display:none;" action="#{myBean.myAction}">
<f:ajax execute="#form" render="#form"></f:ajax>
</h:commandButton>
and set the oncomplete like this:
<p:ajax event="page" oncomplete="$('#call-me-after-page').click();"></p:ajax>

Couldn't write to database using the entity manager persist method

I am about developing a small application using EJB JPA MySQL netbeans7.2,
so my application has the following goal: get the list of names and their IDs and add other names to the list.
My classes are:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.rachid.entities;
import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
#Entity
#Table(name = "employee")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Employee.findAll", query = "SELECT e FROM Employee e"),
#NamedQuery(name = "Employee.findById", query = "SELECT e FROM Employee e WHERE
e.id = :id"),
#NamedQuery(name = "Employee.findByName", query = "SELECT e FROM Employee e WHERE
e.name = :name")})
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Size(max = 20)
#Column(name = "name")
private String name;
public Employee() {
}
public Employee(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Employee)) {
return false;
}
Employee other = (Employee) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "com.rachid.entities.Employee[ id=" + id + " ]";
}
}
The session bean that uses the entity is:
package com.rachid.session;
import com.rachid.entities.Employee;
import java.util.List;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
#Stateless
#LocalBean
public class EmployeeSessionBean {
#PersistenceContext(unitName = "EnterpriseApplication1-ejbPU")
private EntityManager em;
public List<Employee> getAllEmployees() {
Query query = em.createNamedQuery("Employee.findAll");
return query.getResultList();
}
// Add business logic below. (Right-click in editor and choose
// "Insert Code > Add Business Method")
public Employee updateEmployee(Employee parameter) {
return em.merge(parameter);
}
public void addEmployee(Employee employee){
em.persist(employee);
}
}
The managed bean is:
package managedBeans;
import com.rachid.entities.Employee;
import com.rachid.session.EmployeeSessionBean;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.faces.bean.ViewScoped;
import javax.inject.Named;
#Named(value = "employeeManagedBean")
#ViewScoped
public class EmployeeManagedBean implements Serializable {
public EmployeeManagedBean() {
}
#EJB
private EmployeeSessionBean employeeBean;
private Employee employee;
private Employee newEmployee;
private List<Employee> employees;
public List<Employee> getEmployees(){
employees = new ArrayList<Employee>();
return employeeBean.getAllEmployees();
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
public void add(){
if(newEmployee!= null){
employeeBean.addEmployee(newEmployee);
}
}
public String update(){
System.out.println("***UPDATE***");
employee = employeeBean.updateEmployee(employee);
return "Employees List";
}
public Employee getNewEmployee() {
return newEmployee;
}
public void setNewEmployee(Employee newEmployee) {
this.newEmployee = newEmployee;
}
}
Unfortunately, when I invoke the method addEmployee in the jsf page, nothing is written to the database. I was worried about the transaction management handled by the container; that is the updates and inserts are managed by the container and it may not be written to the database immediately, so I annotate the addEmployee method (in the EJB) with the #TransationalAttribute(TransactionalAttributeType.REQUIRED) but the result still the same.
Is there anything that I am missing here in my code or my understanding of the issue's context?
(Note that I am a beginner in EJB :) )
Here are the jsf pages (an index page that shows the list and another one to add new element to the list):
index.xhtml file:
<?xml version='1.0' encoding='UTF-8' ?>
<!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:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
Hello from Facelets
<f:view>
<h:form>
<h1><h:outputText value="List"/></h1>
<h:dataTable value="#{employeeManagedBean.employees}" var="item">
<h:column>
<f:facet name="header">
<h:outputText value="Id"/>
</f:facet>
<h:outputText value="#{item.id}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Name"/>
</f:facet>
<h:outputText value="#{item.name}"/>
</h:column>
</h:dataTable>
</h:form>
</f:view>
<h:form>
<h:commandButton value="nouveau" action="ajouter.xhtml" type="submit" />
</h:form>
</h:body>
ajouter.xhtml file:
<?xml version='1.0' encoding='UTF-8' ?>
<!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:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:body>
<f:view>
<h:form>
<h1><h:outputText value="Create/Edit"/></h1>
<h:panelGrid columns="2">
<h:outputLabel value="Id:" for="id" />
<h:inputText id="id" value="#{employeeManagedBean.newEmployee.id}"
title="Id"
required="true" requiredMessage="The Id field is required."/>
<h:outputLabel value="Name:" for="name" />
<h:inputText id="name" value="#{employeeManagedBean.newEmployee.name}"
title="Name" />
</h:panelGrid>
</h:form>
</f:view>
<h:form>
<h:commandButton value="ajouter" action="index.xhtml" type="submit"
actionListener="#{employeeManagedBean.add()}" />
</h:form>
</h:body>