I Want to get selectOneMenu value in bean but value is not getting correctly.SubstituteHoliday is a boolean variable.But,I getting false only for both yes and no selectItems.How could i get appropriate value for selectOneMenu.Based on that selectOneMenu value if yes means i want to diabled substitue date cell...
Thanks in advance...
<p:dataTable id="manager" var="item" value="#{employeeWorkingHolidayBean.userListTwo}"
paginator="true" rows="10"
paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
rowsPerPageTemplate="2,5,10,15"
editable="true" editMode="cell" style="width:600px;" styleClass="postformatte"
emptyMessage="No Employee Working Holiday Details found with given criteria" resizableColumns="true" >
<p:ajax event="cellEdit" listener="#{employeeWorkingHolidayBean.onCellEdit}"
update=":form:growl"/>
<p:ajax event="colResize" update=":form:growl" listener="#{employeeWorkingHolidayBean.onResize}" />
<p:column headerText="Employee Id" width="90" >
<h:outputText value="#{item.employeeId}" />
</p:column>
<p:column headerText="Is Substitute Holiday">
<p:cellEditor>
<f:facet name="output"><h:outputText value="#{item.substituteHoliday}" /></f:facet>
<f:facet name="input">
<h:selectOneMenu value="#{item.substituteHoliday}" style="width:100%">
<f:selectItems value="#{employeeWorkingHolidayBean.subsholiday}"/>
<p:ajax event="change" update="subdate"/>
</h:selectOneMenu>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Substitute Date" >
<p:cellEditor>
<f:facet name="output"><p:calendar pattern="dd-MM-yyyy" yearRange="#{c-100}" navigator="true" showButtonPanel="true" value="#{item.substituteDate}"/></f:facet>
<f:facet name="input"><p:calendar id="subdate" pattern="dd-MM-yyyy" yearRange="#{c-100}" navigator="true" showButtonPanel="true" value="#{item.substituteDate}" style="width:55px;" disabled="#{employeeWorkingHolidayBean.isdiableEffectdate}"/></f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
Bean:
private Boolean isdiableEffectdate;
public Boolean getIsdiableEffectdate() {
return isdiableEffectdate;
}
public void setIsdiableEffectdate(Boolean isdiableEffectdate) {
this.isdiableEffectdate = isdiableEffectdate;
}
public void onCellEdit(CellEditEvent event)
{
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
logger.info("Old value"+oldValue);
logger.info("New value"+newValue);
if(newValue.equals(true))
{
logger.info("enter if true");
isdiableEffectdate=true;
}
else
{
logger.info("enter if false");
isdiableEffectdate=false;
}
if(newValue != null && !newValue.equals(oldValue))
{
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Cell Changed", "Old: " + oldValue + ", New:" + newValue);
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}
Add a VCE (Value changeListener Event) for your select as,
<h:selectOneMenu value="#{item.substituteHoliday}"
valueChangeListener="#{item.selectHolidayValueChangeListner}"
style="width:100%">
<f:selectItems value="#{employeeWorkingHolidayBean.subsholiday}"/>
<p:ajax event="change" update="subdate"/>
</h:selectOneMenu>
And in your valueChangeListener method assign new value to global variable as,
public void selectHolidayValueChangeListner(ValueChangeEvent vce) {
if (vce.getNewValue() != null) {
substituteHoliday = vce.getNewValue().toString();
}
}
Now, in your ajax method get the value of substituteHoliday and do whatever is required.
Related
I'm working on a theme for an app I'm making with PrimeFaces 6.2 (community edition) and I'd like to get my simulated DAO objects working before I proceed with my css templating.
I've got an issue I came across in the past and I can't find the right answer for it again. Would someone point out an error I've made somewhere in my code?
Details:
I've made a somewhat complex DataTable using PrimeFaces LazyDataModel with little help from PrimeFaces Showcase pages. My main issue is, when I write something in the filter fields or click on any column headers to do data sorting or even click on pagination buttons I get an unexpexted data rendering issue.
Filtered, sorted and paginated results get displayed in a single concatenated row what I don't want. I've posted images and code further below for insight.
Also, I'd like to point out:
No exceptions in JS console.
No exceptions in Java console.
don't mind the missing pagination icons (text-indent: 0;)
XHTML:
<h:form id="input-form-dt2">
<H4>DATA TABLE - LAZY MODEL</H4>
<div class="flex-container">
<p:outputPanel id="dev-input-panel-13">
<p:dataTable var="DOTable" value="#{dtModelLazy.DOTList}" paginator="true" rows="10" rowKey="#{DOTable.userID}"
paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
rowsPerPageTemplate="5,10,15,25,50" selectionMode="single" selection="#{dtModelLazy.selectedObj}" id="DTModelB" lazy="true">
<p:ajax event="rowSelect" listener="#{dtModelLazy.onRowSelect}" update="input-form-dt2:dlgDTOObjDetail" oncomplete="PF('DTObjDialog').show()" />
<p:column headerText="User ID" sortBy="#{DOTable.userID}" filterBy="#{DOTable.userID}" filterMatchMode="contains">
<h:outputText value="#{DOTable.userID}" />
</p:column>
<p:column headerText="Name" sortBy="#{DOTable.name}" filterBy="#{DOTable.name}" filterMatchMode="contains">
<h:outputText value="#{DOTable.name}" />
</p:column>
<p:column headerText="Surname" sortBy="#{DOTable.surname}" filterBy="#{DOTable.surname}" filterMatchMode="contains">
<h:outputText value="#{DOTable.surname}" />
</p:column>
<p:column headerText="Age" sortBy="#{DOTable.age}" filterBy="#{DOTable.age}" filterMatchMode="contains">
<h:outputText value="#{DOTable.age}" />
</p:column>
<p:column headerText="Address" sortBy="#{DOTable.address}" filterBy="#{DOTable.address}" filterMatchMode="contains">
<h:outputText value="#{DOTable.address}" />
</p:column>
<p:column headerText="City" sortBy="#{DOTable.city}" filterBy="#{DOTable.city}" filterMatchMode="contains">
<h:outputText value="#{DOTable.city}" />
</p:column>
<p:column headerText="Post code" sortBy="#{DOTable.postCode}" filterBy="#{DOTable.postCode}" filterMatchMode="contains">
<h:outputText value="#{DOTable.postCode}" />
</p:column>
<p:column headerText="Country code" sortBy="#{DOTable.countryCode}" filterBy="#{DOTable.countryCode}" filterMatchMode="contains">
<h:outputText value="#{DOTable.countryCode}" />
</p:column>
<p:column headerText="Phone number" sortBy="#{DOTable.phoneNumber}" filterBy="#{DOTable.phoneNumber}" filterMatchMode="contains">
<h:outputText value="#{DOTable.phoneNumber}" />
</p:column>
<p:column headerText="Avatar hash" sortBy="#{DOTable.photoID}" filterBy="#{DOTable.photoID}" filterMatchMode="contains">
<h:outputText value="#{DOTable.photoID}" />
</p:column>
</p:dataTable>
<p:dialog id="dlgDTOObjDetail" header="DataTable Object Detail" widgetVar="DTObjDialog" modal="true" showEffect="fade" hideEffect="fade" resizable="false">
<p:outputPanel id="DTObjDetail">
<p:panelGrid columns="2" rendered="#{not empty dtModelLazy.selectedObj}" columnClasses="label,value">
<h:outputText value="User ID: " />
<h:outputText value="#{dtModelLazy.selectedObj.userID}" />
<h:outputText value="Name: " />
<h:outputText value="#{dtModelLazy.selectedObj.name}" />
<h:outputText value="Surname: " />
<h:outputText value="#{dtModelLazy.selectedObj.surname}" />
<h:outputText value="Age: " />
<h:outputText value="#{dtModelLazy.selectedObj.age}" />
<h:outputText value="Address: " />
<h:outputText value="#{dtModelLazy.selectedObj.address}" />
<h:outputText value="City: " />
<h:outputText value="#{dtModelLazy.selectedObj.city}" />
<h:outputText value="Post code: " />
<h:outputText value="#{dtModelLazy.selectedObj.postCode}" />
<h:outputText value="Country code: " />
<h:outputText value="#{dtModelLazy.selectedObj.countryCode}" />
<h:outputText value="Phone number: " />
<h:outputText value="#{dtModelLazy.selectedObj.phoneNumber}" />
<h:outputText value="Photo hash: " />
<h:outputText value="#{dtModelLazy.selectedObj.photoID}" />
</p:panelGrid>
</p:outputPanel>
</p:dialog>
</p:outputPanel>
</div>
<hr></hr>
</h:form>
LAZY MODEL:
public class DataTableModelLazy extends LazyDataModel<DODataTable> {
private static final long serialVersionUID = -2647349397077805782L;
private List<DODataTable> datasource;
public DataTableModelLazy(List<DODataTable> datasource) {
this.datasource = datasource;
}
#Override
public DODataTable getRowData(String rowKey) {
for(DODataTable dtObj : datasource) {
if(dtObj.getUserID().equals(rowKey))
return dtObj;
}
return null;
}
#Override
public Object getRowKey(DODataTable dtObj) {
return dtObj.getUserID();
}
#Override
public List<DODataTable> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String,Object> filters) {
List<DODataTable> data = new ArrayList<DODataTable>();
//filter
for(DODataTable dtObj : datasource) {
boolean match = true;
if(filters != null) {
for (Iterator<String> it = filters.keySet().iterator(); it.hasNext();) {
try {
String filterProperty = it.next();
Object filterValue = filters.get(filterProperty);
Field field = dtObj.getClass().getDeclaredField(filterProperty);
field.setAccessible(true);
String fieldValue = String.valueOf(field.get(dtObj));
field.setAccessible(false);
if(filterValue == null || fieldValue.startsWith(filterValue.toString())) {
match = true;
} else {
match = false;
break;
}
} catch(Exception e) {
match = false;
}
}
}
if(match) {
data.add(dtObj);
}
}
//sort
if(sortField != null) {
Collections.sort(data, new DataTableModelLazySorter(sortField, sortOrder));
}
//rowCount
int dataSize = data.size();
this.setRowCount(dataSize);
//paginate
if(dataSize > pageSize) {
try {
return data.subList(first, first + pageSize);
} catch(IndexOutOfBoundsException e) {
return data.subList(first, first + (dataSize % pageSize));
}
} else {
return data;
}
}
}
VIEW BEAN:
#Named("dtModelLazy")
#ViewScoped
public class DataGeneratorBeanLazy implements Serializable {
private static final long serialVersionUID = -5918527333909822277L;
private LazyDataModel<DODataTable> DOTList;
private DODataTable selectedObj;
#Inject
private DataGeneratorBean dataGen;
#PostConstruct
public void init() {
DOTList = new DataTableModelLazy(dataGen.createDTObjects(1500));
}
public LazyDataModel<DODataTable> getDOTList() {
return DOTList;
}
public void setDOTList(LazyDataModel<DODataTable> dOTList) {
DOTList = dOTList;
}
public void onRowSelect(SelectEvent event) {
FacesMessage msg = new FacesMessage("DataTable object selected!", ((DODataTable) event.getObject()).getUserID());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public DODataTable getSelectedObj() {
return selectedObj;
}
public void setSelectedObj(DODataTable selectedObj) {
this.selectedObj = selectedObj;
}
}
Update 1
I have modified the update property as update="input-form-dt2:dlgDTOObjDetail"to meet the suggestion provided. Also, I added the id property for the dialog. The issue still remains.
Update 2
I've changed my approach and started with the basic DataTable first. Also, I've stripped the .xhtml to a bare minimum. It contains only a form with the DataTable inside like so:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui">
<div>
UI components design
</div>
<h:form id="input-form-dt1">
<h4>DATA TABLE - BASIC</h4>
<p:dataTable id="DTableA" var="dataObject" value="#{dataTableBean.objectList}" paginator="true" rows="10" rowKey="#{dataObject.id}"
paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
rowsPerPageTemplate="5,10,15,25,50">
<p:column headerText="User ID" sortBy="#{dataObject.userID}" filterBy="#{dataObject.userID}" filterMatchMode="contains">
<h:outputText value="#{dataObject.userID}" />
</p:column>
<p:column headerText="Name" sortBy="#{dataObject.name}" filterBy="#{dataObject.name}" filterMatchMode="contains" >
<h:outputText value="#{dataObject.name}" />
</p:column>
<p:column headerText="Surname" sortBy="#{dataObject.surname}" filterBy="#{dataObject.surname}" filterMatchMode="contains" >
<h:outputText value="#{dataObject.surname}" />
</p:column>
<p:column headerText="Age" sortBy="#{dataObject.age}" filterBy="#{dataObject.age}" filterMatchMode="contains" >
<h:outputText value="#{dataObject.age}" />
</p:column>
<p:column headerText="Address" sortBy="#{dataObject.address}" filterBy="#{dataObject.address}" filterMatchMode="contains" >
<h:outputText value="#{dataObject.address}" />
</p:column>
<p:column headerText="City" sortBy="#{dataObject.city}" filterBy="#{dataObject.city}" filterMatchMode="contains" >
<h:outputText value="#{dataObject.city}" />
</p:column>
<p:column headerText="Post code" sortBy="#{dataObject.postCode}" filterBy="#{dataObject.postCode}" filterMatchMode="contains" >
<h:outputText value="#{DOTable.postCode}" />
</p:column>
<p:column headerText="Country code" sortBy="#{dataObject.countryCode}" filterBy="#{dataObject.countryCode}" filterMatchMode="contains" >
<h:outputText value="#{dataObject.countryCode}" />
</p:column>
<p:column headerText="Phone number" sortBy="#{dataObject.phoneNumber}" filterBy="#{dataObject.phoneNumber}" filterMatchMode="contains" >
<h:outputText value="#{dataObject.phoneNumber}" />
</p:column>
<p:column headerText="Avatar hash" sortBy="#{dataObject.photoID}" filterBy="#{dataObject.photoID}" filterMatchMode="contains">
<h:outputText value="#{dataObject.photoID}" />
</p:column>
</p:dataTable>
</h:form>
</ui:composition>
As you can see I've also removed all event listeners. I've added a new field to my data object (id of type Integer) and bound DataTables rowKey to it (previously bound to userID of type String - not a good idea). My DataTable backing bean is now as basic as it can be:
#Named("dataTableBean")
#ViewScoped
public class DataTableBean implements Serializable {
private static final long serialVersionUID = -1662465661106141910L;
private List<DTObject> objectList;
#Inject
private DataGeneratorBean dataGen;
#PostConstruct
public void init() {
setObjectList(dataGen.createDTObjects(1500));
}
public List<DTObject> getObjectList() {
if (objectList == null) {
return new ArrayList<>();
} else {
return objectList;
}
}
public void setObjectList(List<DTObject> objectList) {
this.objectList = objectList;
}
}
Now, there are no custom filters, sorters or paginators of any type, not even a data model, just raw data objects in a simple list. The output result is exactly the same as before when paginator buttons are clicked or data gets filtered. All resulting data still gets displayed in a single concatenated line.
ANSWER:
As Kukeltje pointed out in the comments I've made a complete nonsense in my main container and added an autoupdate component to it. That component messed up my data table events, loading data without a table to hold it. Once I've removed the component from my main container, everything worked out. Here is the code for my main container (commented out the troublemaker).
<div id="content-window">
<p:outputPanel id="content-panel">
<ui:include src="#{contentLoaderBean.mainContent}" />
<!-- <p:autoUpdate /> -->
</p:outputPanel>
</div>
The only situations I've seen this happening is when the datatable is fully updated in addtion to a partial update of the datatable via an event (page or filter or sort or...) In the rowSelect you do seem to update the full form which contains the datatable as well. That is bad practice and can as mentioned result in what you seem so remove that.
But...in your question there are no filter ajax events that explicitly update the full datatable so that cannot cause it. Yet with 99% vertainty there is something fully updates the datatable. Three options
there is something in your live code you left out of the datatable in your question
There is something else outside the code you posted that plays havoc (an autoupdate e.g),
an update from the server side is being done in a method
i got an error on my datatable "Target Unreachable, 'null' returned null", it caused by one column with join with another table, normally i initiate everything in my beans, this is my code, someone can enlighten me please ?
#ManagedBean
#ViewScoped
public class locationBean extends LazyDataModel<Location> {
private Location selectedLocation;
private List<Location> locations;
private List<SelectItem> selectoneitemclient;
#PostConstruct
public void init() {
this.locations = new ArrayList<Location>();
this.selectoneitemclient = new ArrayList<SelectItem>();
this.selectedLocation = new Location();
}
public List<SelectItem> getSelectoneitemclient() {
ClientDao clientdao = new ClientDaoImpl();
List<Client> clients = clientdao.selectItems();
for (Client cl : clients) {
SelectItem selectitem = new SelectItem(cl.getCodecl(), cl.getNom());
this.selectoneitemclient.add(selectitem);
}
return selectoneitemclient;
}
public List<Location> getLocations() {
LocationDao locationdao = new LocationDaoImpl();
this.locations = locationdao.findAll();
return locations;
}
location.xhtml
<h:form id="formDataTable">
<p:dataTable var="location" value="#{locationBean.locations}" rowKey="#{location.codeloc}" paginatorPosition="bottom" paginator="true" rows="10"
paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
rowsPerPageTemplate="5,10,15" selectionMode="single" selection="#{locationBean.selectedLocation}" id="tableLocation">
<p:ajax event="rowSelect" listener="#{locationBean.onRowSelect}" update=":formDisplay" oncomplete="PF('dialogLocationDisplay').show()" />
<f:facet name="header">
Listes des réservations
</f:facet>
<p:column headerText="Type client" filterBy="#{location.client.typecl}"
footerText="contains"
filterMatchMode="contains">
<h:outputText value="#{location.client.typecl}" />
</p:column>
<p:column headerText="Nom" filterBy="#{location.client.nom}"
footerText="contains"
filterMatchMode="contains">
<h:outputText value="#{location.client.nom}" />
</p:column>
<p:column headerText="Tel" filterBy="#{location.client.tel}"
footerText="contains"
filterMatchMode="contains">
<h:outputText value="#{location.client.tel}" />
</p:column>
<p:column headerText="Email" filterBy="#{location.client.email}"
footerText="contains"
filterMatchMode="contains">
<h:outputText value="#{location.client.email}" />
</p:column>
<p:column headerText="Date Debut" filterBy="#{location.datedebut}"
footerText="contains"
filterMatchMode="contains">
<h:outputText value="#{location.datedebut}" />
</p:column>
<p:column headerText="Date Fin" filterBy="#{location.datefin}"
footerText="contains"
filterMatchMode="contains">
<h:outputText value="#{location.datefin}" />
</p:column>
<p:column headerText="Gestion">
<p:commandButton id="btnUpdate" update=":formUpdate" oncomplete="PF('dialogLocationUpdate').show()" icon="ui-icon-pencil" title="modifier">
<f:setPropertyActionListener value="#{location}" target="#{locationBean.selectedLocation}"/>
</p:commandButton>
<p:commandButton id="btnDelete" update=":formDelete" oncomplete="PF('dialogLocationDelete').show()" icon="ui-icon-trash" title="supprimer">
<f:setPropertyActionListener value="#{location}" target="#{locationBean.selectedLocation}"/>
</p:commandButton>
</p:column>
</p:dataTable>
</h:form>
<h:form id="formUpdate">
<p:dialog header="modifier une reservation" widgetVar="dialogLocationUpdate" modal="true" showEffect="fade" hideEffect="fade" resizable="false">
<p:outputPanel id="detailLocationUpdate" style="text-align:center;">
<p:panelGrid columns="2" columnClasses="label,value">
<h:outputText value="Client: " />
<p:selectOneMenu value="#{locationBean.selectedLocation.client.codecl}">
<f:selectItem itemLabel="- Selectionner un client -" itemValue = "" />
<f:selectItems value="#{locationBean.selectoneitemclient}" />
</p:selectOneMenu>
<h:outputText value="Titre: " />
<p:inputText value="#{locationBean.selectedLocation.titre}" />
LocationDaoImpl.java
#Override
public List<Location> findAll() {
List<Location> listloc = null;
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
String sql = "FROM Location l inner join fetch l.client";
try {
session.beginTransaction();
listloc = session.createQuery(sql).list();
session.beginTransaction().commit();
} catch (Exception e) {
if (session != null) {
session.close();
}
e.printStackTrace();
}
return listloc;
}
#Override
public boolean update(Location loc) {
boolean flag;
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
try {
session.beginTransaction();
Location locdb = (Location) session.load(Location.class, loc.getCodeloc());
locdb.setCodeloc(loc.getCodeloc());
locdb.setTitre(loc.getTitre());
locdb.setClient(loc.getClient());
locdb.setDatedebut(loc.getDatedebut());
locdb.setDatefin(loc.getDatefin());
locdb.setTotalttc(loc.getTotalttc());
session.update(locdb);
session.getTransaction().commit();
flag = true;
} catch (Exception e) {
flag = false;
if (session != null) {
session.close();
}
e.printStackTrace();
}
return flag;
}
I'm developing a web-app with JSF 2.1 + Primefaces 5.1. I have a datatable with row edition and each row has 2 inputText, 2 selectOneMenu and 1 selectBooleanCheckbox. I want to perform some business logic validation when clicking the check icon: it will validate the values of the 2 selectOneMenus. For that, I created a custom validator associated with the second selectOneMenu that validates both values:
<p:dataTable id="users_table_id" var="user" value="#{usersBean.users}" rowKey="#{user.id}" paginator="true"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="5,10,15" emptyMessage="#{msgs.no_records}" sortBy="#{user.id}" sortOrder="ascending" rows="15" editable="true">
<f:facet name="header">
#{msgs.users}
</f:facet>
<p:ajax event="rowEdit" listener="#{usersBean.onRowEdit}" update=":users_form_id:growl"/>
<p:ajax event="rowEditInit" listener="#{usersBean.onRowEditInit}" update=":users_form_id:growl"/>
<p:ajax event="rowEditCancel" listener="#{usersBean.onRowEditCancel}" update=":users_form_id:growl"/>
<p:column headerText="#{msgs.id}" sortBy="#{user.id}" styleClass="centered-column">
#{user.id}
</p:column>
<p:column headerText="#{msgs.description}" sortBy="#{user.description}" styleClass="centered-column">
<p:cellEditor>
<f:facet name="output">#{user.description}</f:facet>
<f:facet name="input"><p:inputText value="#{user.description}" styleClass="editable-cell"/></f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="#{msgs.password}" sortBy="#{user.password}" styleClass="centered-column">
<p:cellEditor>
<f:facet name="output">#{user.password}</f:facet>
<f:facet name="input"><p:inputText value="#{user.password}" styleClass="editable-cell"/></f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="#{msgs.sending_system}" sortBy="#{user.playerIn.description}" styleClass="centered-column">
<p:cellEditor>
<f:facet name="output">#{user.playerIn.description}</f:facet>
<f:facet name="input">
<p:selectOneMenu binding="#{userPlayerInComponent}" styleClass="editable-cell" id="users_table_sending_system_id" value="#{user.playerIn}" effectSpeed="fast" filter="true" filterMatchMode="contains" converter="#{playerConverter}">
<f:selectItem itemLabel="#{msgs.select_option}" itemValue="#{null}" noSelectionOption="true"/>
<f:selectItems value="#{usersBean.players}" var="player" itemValue="#{player}" itemLabel="#{player.description}"/>
</p:selectOneMenu>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="#{msgs.receiving_system}" sortBy="#{user.playerOut.description}" styleClass="centered-column">
<p:cellEditor>
<f:facet name="output">#{user.playerOut.description}</f:facet>
<f:facet name="input">
<p:selectOneMenu styleClass="editable-cell" id="users_table_receiving_system_id" value="#{user.playerOut}" effectSpeed="fast" filter="true" filterMatchMode="contains" converter="#{playerConverter}">
<f:selectItem itemLabel="#{msgs.select_option}" itemValue="#{null}" noSelectionOption="true"/>
<f:selectItems value="#{usersBean.players}" var="player" itemValue="#{player}" itemLabel="#{player.description}"/>
<f:validator validatorId="userValidator"/>
<f:attribute name="userPlayerInComponent" value="#{userPlayerInComponent}"/>
</p:selectOneMenu>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="#{msgs.active}" sortBy="#{user.active}" styleClass="centered-column">
<p:cellEditor>
<f:facet name="output"><p:selectBooleanCheckbox value="#{user.active}" disabled="true"/></f:facet>
<f:facet name="input"><p:selectBooleanCheckbox value="#{user.active}"/></f:facet>
</p:cellEditor>
</p:column>
<p:column styleClass="datatable-row-editor">
<p:rowEditor/>
</p:column>
<f:facet name="footer">
</f:facet>
</p:dataTable>
#FacesValidator("userValidator")
public class UserValidator implements Validator {
private static final Logger logger = LogManager.getLogger(UserValidator.class);
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
logger.entry(context, component, value);
if (value == null) {
return; // Let required="true" handle.
}
UIInput userPlayerInComponent = (UIInput)component.getAttributes().get("userPlayerInComponent");
if (!userPlayerInComponent.isValid()) {
return; // Already invalidated. Don't care about it then.
}
DtoPlayer playerIn = (DtoPlayer)userPlayerInComponent.getValue();
if (playerIn == null) {
return; // Let required="true" handle.
}
DtoPlayer playerOut = (DtoPlayer)value;
UsersBean usersBean = context.getApplication().evaluateExpressionGet(context, "#{usersBean}", UsersBean.class);
BigDecimal userId = usersBean.getUserEditingId();
logger.info(userId + " - " + playerIn.getDescription() + " - " + playerOut.getDescription());
for (DtoUser dtoUser : usersBean.getUsers()) {
if (!userId.equals(dtoUser.getId()) && dtoUser.getPlayerIn().equals(playerIn) && dtoUser.getPlayerOut().equals(playerOut)) {
logger.info("Invalidating...");
userPlayerInComponent.setValid(false);
FacesContext.getCurrentInstance().validationFailed();
throw new ValidatorException(new FacesMessage("BOOM!"));
}
}
logger.exit();
}
}
I was expecting that, when validation fails (and a ValidatorException is thrown), the datatable row would stay in edit mode and the two selectOneMenus highlighted with red colour. But what happens is that the row exits from edit mode, keeping the old values. If I edit it again, it displays the submitted values and the invalid cells are marked with red. And this behaviour continues as long as I try to submit the invalid values. If I close the edit mode, the invalid values are discarded and the row keeps only the old values (whether in view or edit mode).
How can I solve this? From the Primefaces' showcase, one can see that when you try to submit, let's say, a string with alfabetic characters in the year cell, the row keeps the edit mode and is highlighted. I want to achieve the same behaviour.
I have two primefaces dataTables. The first show the instances of a MainEntity.
The second one show a list of Words (just strings) associated with the selected MainEntity on the first datatable.
The printscreen illustrates what I mean.
My problem is, when I edit a string on the Word List, my listener method won't receive the new value. In fact, when I call the event.getNewValue() method, I get old value.
What am I missing?
I'm using JavaServer Faces 2.2, Primefaces 5.0 and Spring Framework 4.0.3.
Thanks in advance for any help.
The code for the xhtml, the managed bean and the MainEntity are as follows:
mainEntity.xhtml:
<h:body>
<h:form id="mainEntityForm">
<p:panelGrid columns="1" fullPage="true" id="dashboard">
<f:facet name="header">
<h2>MainEntity Table</h2>
</f:facet>
<p:panel>
<f:facet name="header">
MainEntity List
<p:commandButton value="New MainEntity"
actionListener="#{mainEntityController.createMainEntityDialog}"
styleClass="header-button">
<p:ajax event="dialogReturn" update=":mainEntityForm:mainEntityTable" />
</p:commandButton>
</f:facet>
<p:dataTable id="mainEntityTable" var="mainEntity" value="#{mainEntityController.mainEntities}"
editable="true" editMode="cell" widgetVar="cellMainEntity"
selectionMode="single" selection="#{mainEntityController.selectedMainEntity}"
rowKey="#{mainEntity.id}" tableStyle="width:auto">
<p:ajax event="rowSelect" update=":mainEntityForm:stringGrid :mainEntityForm:entityAGrid :mainEntityForm:entityBGrid" />
<p:ajax event="cellEdit" listener="#{mainEntityController.onEditMainEntity}" update=":mainEntityForm:mainEntityTable" />
<p:column headerText="ID">
<h:outputText value="#{mainEntity.id}" />
</p:column>
<p:column headerText="Name">
<p:cellEditor>
<f:facet name="output">
<h:outputText id="nameOutput" value="#{mainEntity.name}" />
</f:facet>
<f:facet name="input">
<h:inputText id="atyInput" value="#{mainEntity.qty}" />
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Commands">
<p:commandButton title="Remove MainEntity" icon="ui-icon-trash"
actionListener="#{mainEntityController.deleteMainEntity(mainEntity)}"
update=":mainEntityForm:mainEntityTable" />
</p:column>
</p:dataTable>
</p:panel>
<p:panelGrid fullPage="true" id="mainEntityDetail">
<f:facet name="header">
<p:row>
<p:column colspan="4">
<h2>MainEntity Detail</h2>
</p:column>
</p:row>
</f:facet>
<p:row>
<p:column>
<p:panel>
<f:facet name="header">
Word List
<p:commandButton value="New Word"
actionListener="#{mainEntityController.addNewWord()}"
styleClass="header-button"
update=":mainEntityForm:wordGrid">
</p:commandButton>
</f:facet>
<p:dataTable id="wordGrid" var="word"
value="#{mainEntityController.selectedMainEntity.wordList}"
tableStyle="width:auto" editable="true" editMode="cell" widgetVar="cellWord">
<p:ajax event="cellEdit" listener="#{mainEntityController.onEditWord}" />
<p:column headerText="Word">
<p:cellEditor>
<f:facet name="output">
<h:outputText id="wordOutput" value="#{word}" />
</f:facet>
<f:facet name="input">
<h:inputText id="wordInput" value="#{word}" />
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Commands">
<p:commandButton title="Remove Word"
icon="ui-icon-trash"
actionListener="#{mainEntityController.removeWord(word)}"
update=":mainEntityForm:wordGrid" />
</p:column>
</p:dataTable>
</p:panel>
</p:column>
</p:row>
</p:panelGrid>
</p:panelGrid>
</h:form>
</h:body>
MainEntityController.java (managed bean):
#ManagedBean
#SessionScoped
public class MainEntityController {
//...
private MainEntity selectedMainEntity;
public List<MainEntity> mainEntities;
//...
public MainEntity getSelectedMainEntity(){
return selectedMainEntity;
}
public void setSelectedMainEntity(MainEntity mainEntity){
this.selectedMainEntity = mainEntity;
}
//...
public void onEditWord(CellEditEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
if(newValue != null && !newValue.equals(oldValue)) {
// THE PROBLEM IS HERE
// I NEVER ACTUALLY REACH THIS CODE
// newValue is always equal to oldValue!
FacesContext context = FacesContext.getCurrentInstance();
String word = context.getApplication().evaluateExpressionGet(context, "#{word}", String.class);
System.out.println(newValue);
System.out.println(word);
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Word Changed", "Old: " + oldValue + ", New:" + newValue);
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}
}
MainEntity.java:
#Entity
public class MainEntity {
#Id
private String id;
#ElementCollection(fetch=FetchType.EAGER)
#CollectionTable(
name="MainEntity_Word",
joinColumns = #JoinColumn(name = "id", referencedColumnName="id")
)
#Column(name = "word")
private Set<String> wordList;
//...
public void addWord(String word) {
this.wordList.add(word);
}
public void removeWord(String word) {
this.wordList.remove(word);
}
public Set<String> getWordList() {
return wordList;
}
public void setWordList(Set<String> wordList) {
this.wordList = wordList;
}
}
Change
<h:inputText id="wordInput" value="#{word}" />
to
<p:inputText id="wordInput" value="#{word}" />
or
<h:inputText id="wordInput" value="#{word}" >
<p:ajax event="change" process="#this"/>
</h:inputText>
You need to ajaxify the input component, and at last update the outputText component.
Edited:
change this column :
<p:column headerText="Word" >
<p:cellEditor>
<f:facet name="output">
<h:outputText id="wordOutput" value="#{word}" />
</f:facet>
<f:facet name="input">
<h:inputText id="wordInput" value="#{word}" />
</f:facet>
</p:cellEditor>
</p:column>
to
<p:column headerText="Word" >
<p:cellEditor>
<f:facet name="output">
<h:outputText id="wordOutput" value="#{word}" />
</f:facet>
<f:facet name="input">
<p:inputText id="wordInput" value="#{word}" >
<p:ajax event="change" update="wordOutput" />
</p:inputText>
</f:facet>
</p:cellEditor>
</p:column>
Edit 2 :
From Chapter 24 Introduction to the Java Persistence API
If an entity instance be passed by value as a detached object, such as
through a session bean’s remote business interface, the class must
implement the Serializable interface.
I finally got it working.
I suspected of the String immutable nature and what I did was to encapsulate the 'word' in a class like the following:
public class Word {
private String word;
Word (String word) {
this.setWord(word);
}
public String getWord() {
return this.word;
}
public void setWord(String word) {
this.word = word;
}
}
After that, I also had to create a set inside the managed bean (controller) to hold the set of words, like 'private Set managedWordList;'.
I also changed the getter for the list, inside the managed bean, to convert from the String set to a Word set like:
public Set<Word> getWordList() {
if (this.selectedMainEntity != null){
this.wordList = new HashSet<Word>();
for (String word : this.selectedMainEntity.getWordList()) {
this.wordList.add(new Word(word));
}
}
return this.wordList;
}
Finally, I changed the dataTable to reference the new set. From:
<p:dataTable ... value="#{mainEntityController.selectedMainEntity.wordList}"... />
To:
<p:dataTable ... value="#{mainEntityController.wordList}"... />
And only then I got it to work as I expected.
i am trying to implement a primefaces data table with cell editing. Something similar to the one implemented here:
http://www.primefaces.org/showcase/ui/datatableCellEditing.jsf
So here is my jsf datatable code:
<h:form>
<p:growl id="messages" showDetail="true"/>
<p:panel id="dataPanel">
<p:dataTable
id="imagesDataTable"
var="cRImageData"
value="#{syncCenterBean.cRImageDataList}"
widgetVar="imagesTable"
paginator="true"
sortMode="multiple"
rows="10"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="10,15,20,30"
paginatorAlwaysVisible="false"
editable="true"
editMode="cell">
<p:ajax event="cellEdit" listener="#{syncCenterBean.onCellEdit}" update=":form:messages" />
<p:column sortBy="#{cRImageData.imId}" headerText="ID" style="width:100px;text-align:center;">
<h:outputText value="#{cRImageData.imId}" />
</p:column>
<p:column headerText="Image Name" style="width:180px;text-align:center;">
<h:outputText value="#{cRImageData.imName}" />
</p:column>
<p:column headerText="Image Type" style="width:170px;text-align:center;">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{cRImageData.imType}" />
</f:facet>
<f:facet name="input">
<h:selectOneMenu value="#{syncCenterBean.cRImageTypeList}" style="width:100%">
<f:selectItems value="#{syncCenterBean.cRImageTypeList}" var="imTypeId" itemLabel="#{imTypeId}" itemValue="#{imTypeId}" />
</h:selectOneMenu>
</f:facet>
</p:cellEditor>
</p:column>
...
And here is the code for my back bean:
#ManagedBean(name = "syncCenterBean")
#RequestScoped
public class SyncCenterBean implements Serializable {
....
List<CRImageData> cRImageDataList;
List<CRImageType> cRImageTypeList;
#SuppressWarnings("unchecked")
public SyncCenterBean(){
cRImageTypeList = getImageTypesDB(); //returns a populated list of objects
cRImageDataList = getImageDataDB(); //returns a populated list of objects
}
...
public void onCellEdit(CellEditEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
if(newValue != null && !newValue.equals(oldValue)) {
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Cell Changed", "Old: " + oldValue + ", New:" + newValue);
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}
But when i try to load the view i get:
Caused by: javax.faces.view.facelets.TagException: .... Event:cellEdit is not supported.
on line:
<p:ajax event="cellEdit" listener="#{syncCenterBean.onCellEdit}" update=":form:messages" />
You should make your datatable editable for this event
<p:datatable editable="true" editMode="cell" />