I have a primefaces dataTable that displays data from several database tables. A selection list allows the user to select the specific database table to display. It works as expected except when the dataTable filtering capability is used. For example, when a user selects 'DEPT' from the selection list, the dataTable is rendered with data from the DEPT table. The user can select other tables normally. However, if the user selects another table called 'EMP' after filtering, the dataTable fails to render with the following exception:
javax.el.PropertyNotFoundException: The class 'example.dto.Dept' does not have the property 'firstName'.
at javax.el.BeanELResolver.getBeanProperty(BeanELResolver.java:576)
at javax.el.BeanELResolver.getValue(BeanELResolver.java:291)
at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:156)
Here's the .xhtml file:
<h:form prependId="false">
<p:outputLabel for="selTbl" value="Select a table:" />
<p:autoComplete id="selTbl" value="#{mainBean.selectedTable}"
completeMethod="#{mainBean.filterAuditTables}" cache="true" dropdown="true" effect="fade"
minQueryLength="3" forceSelection="true" size="35" style="margin-left: 10px;">
<p:ajax event="itemSelect" listener="#{mainBean.onTableSelect}" process="#this" update="#form" />
</p:autoComplete>
<p:dataTable id="audTblData" value="#{mainBean.data}" var="row"
filteredValue="#{mainBean.filteredData}" resizableColumns="true" resizeMode="expand"
sortMode="multiple">
<f:facet name="header">
<h:outputText value="#{mainBean.selectedTable}" />
</f:facet>
<p:columns value="#{mainBean.tableColumns}" var="col" sortBy="#{row[col.property]}"
filterBy="#{row[col.property]}" filterMatchMode="contains">
<f:facet name="header">
<h:outputText value="#{col.header}" />
</f:facet>
<h:outputText value="#{row[col.property]}" />
</p:columns>
</p:dataTable>
</h:form>
MainBean.java:
#Named
#ViewScoped
public class MainBean implements Serializable {
private static final long serialVersionUID = 1L;
// these are used for the audited table selection list
private List<String> auditedTables;
private String selectedTable;
// these are used in the table that displays the audit data
private List<ColumnModel> tableColumns;
private List<Auditable> data;
private List<Auditable> filteredData;
#Inject
private AudviewService audviewService;
#PostConstruct
public void init() {
auditedTables = audviewService.getAuditedTables();
}
public List<String> filterAuditTables(String query) {
return auditedTables
.stream()
.filter(t -> t.contains(query.toUpperCase()))
.collect(Collectors.toList());
}
public void onTableSelect(SelectEvent<String> event) {
retrieveTableData();
}
public void retrieveTableData() {
List<String> columns = audviewService.listTableColumns(selectedTable);
// initialize columns for <p:dataTable>
tableColumns = new ArrayList<ColumnModel>();
for (String col : columns) {
tableColumns.add(new ColumnModel(col, AudviewUtil.columnToProperty(col)));
}
// retrieve data for the selected table
data = audviewService.getTableData(selectedTable);
}
/* getters and setters */
}
Note that Auditable is an interface implemented by Dept.java and Emp.java.
As you noticed, the problem is switching from a filtered or sorted datatable to another, if the filtered or sorted column is a field that isn't in the new selected class. An easy solution would be moving all the needed fields into the superclass Auditable.
Another approach is separating datatable resetting&updating in two steps, here a possible solution (I replace, for testing purpose, your service with static code, so there could be some errors adapting my solution to your code):
xhtml
<h:form id="formTbl" prependId="false">
<p:outputLabel for="selTbl" value="Select a table:" />
<p:autoComplete id="selTbl" value="#{mainBean.selectedTable}"
completeMethod="#{mainBean.filterAuditTables}" cache="true"
dropdown="true" effect="fade" minQueryLength="3"
forceSelection="true" size="35" style="margin-left: 10px;">
<p:ajax event="itemSelect" listener="#{mainBean.onTableSelect}"
process="#this" onstart="PF('vtWidget').clearFilters()" />
</p:autoComplete>
<p:remoteCommand name="btn" process="#this" update="audTblData" />
<p:dataTable id="audTblData" value="#{mainBean.data}" var="row"
filteredValue="#{mainBean.filteredData}" resizableColumns="true"
resizeMode="expand" sortMode="multiple" widgetVar="vtWidget">
<f:facet name="header">
<h:outputText value="#{mainBean.selectedTable}" />
</f:facet>
<p:columns value="#{mainBean.tableColumns}" var="col"
sortBy="#{row[col.property]}" filterBy="#{row[col.property]}"
filterMatchMode="contains">
<f:facet name="header">
<h:outputText value="#{col.header}" />
</f:facet>
<h:outputText value="#{row[col.property]}" />
</p:columns>
</p:dataTable>
</h:form>
java
public void retrieveTableData() {
List<String> columns = listTableColumns(selectedTable);
// initialize columns for <p:dataTable>
tableColumns = new ArrayList<ColumnModel>();
for (String col : columns) {
tableColumns.add(new ColumnModel(col + " header", col));
}
// retrieve data for the selected table
data = getData(selectedTable);
DataTable dataTable = (DataTable) FacesContext.getCurrentInstance().getViewRoot().findComponent("formTbl:audTblData");
if (dataTable != null) {
dataTable.reset();
}
PrimeFaces.current().executeScript("btn()");
}
Pay attention, if you need also to manage pagination.
I'm facing a huge problem since 2 weeks.
I tested 2 ajax method one by one and they work. But when I want to have both in a oneMenu, the dropdown supposed to update the third oneMenu of the page does'nt work.
<h:body>
<h:form>
<p:growl id="growl" showDetail="true" />
<p:outputLabel value="Sélectionner une section " for="sectionBox"/>
<p:selectOneMenu id="sectionBox"
value="#{evaluationViewController.currentSection}"
converter="sectionConverter"
var="c"
filter="true"
filterMatchMode="startsWith"
effect="fade"
>
<p:ajax listener="#{evaluationViewController.onSectionSelected}" update="ue,ueO,growl"/>
<f:selectItem itemLabel="Sélectionnez uen section" itemValue="" noSelectionOption="true"/>
<f:selectItems value="#{evaluationViewController.currentSections}"
var="currentSection"
itemLabel="#{currentSection.name}"
itemValue="#{currentSection}"
/>
<p:column>
<h:outputText value="#{c.name}"/>
</p:column>
</p:selectOneMenu>
<p:outputLabel value="Sélectionner une UE " for="ue"/>
<p:selectOneMenu id="ue"
value="#{evaluationViewController.ue}"
converter="ueConverter"
var="u"
filter="true"
filterMatchMode="startsWith"
>
<p:ajax listener="#{evaluationViewController.onUeSelected}" update="ueO,growl"/>
<p:ajax event="change" update="capacities" listener="#{evaluationViewController.listenerCapacitiesUpdate}"/>
<f:selectItem itemLabel="Sélectionnez une UE" itemValue="" noSelectionOption="true"/>
<f:selectItems value="#{evaluationViewController.ues}"
var="ues"
itemLabel="#{ues.name}"
itemValue="#{ues}"
/>
<p:column>
<h:outputText value="#{u.name}"/>
</p:column>
</p:selectOneMenu>
<p:outputLabel value="Sélectionner l'UE enseignée" for="ueO"/>
<p:selectOneMenu id="ueO"
value="#{evaluationViewController.organizedUe}"
converter="organizedUeConverter"
var="o"
filter="true"
filterMatchMode="startsWith"
>
<f:selectItem itemLabel="Sélectionnez une année" itemValue="" noSelectionOption="true"/>
<f:selectItems
value="#{evaluationViewController.organizedUes}"
var="organizedUes"
itemLabel="#{organizedUes.name}"
itemValue="#{organizedUes}"
/>
<p:column>
<h:outputText value="#{o.name}"/>
</p:column>
<p:column>
<h:outputText value="#{o.level.name}"/>
</p:column>
</p:selectOneMenu>
<p:separator/>
<p:separator/>
<p:dataTable id="capacities"
var="cap"
value="#{evaluationViewController.capacities}"
editable="true"
editMode="cell"
widgetVar="cellCap"
>
<f:facet name ="header">
Capacitées
</f:facet>
<p:ajax event="cellEdit"
listener="#{evaluationViewController.onCellEdit}"
update="#this"/>
<p:column headerText="Dénomination">
<p:cellEditor>
<f:facet name="output"><h:outputText value="#{cap.name}"/></f:facet>
<f:facet name="input"><p:inputText value="#{cap.name}" style="width: 30%" label="Dénomination"/></f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Description">
<p:cellEditor>
<f:facet name="output"><h:outputText value="#{cap.description}"/></f:facet>
<f:facet name="input"><h:inputText value="#{cap.description}" style="width: 90%" label="Description"/></f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Réussite obligatoire">
<p:selectBooleanCheckbox value="#{cap.isThresholdOfSuccess}" style="alignment-adjust: central"/>
</p:column>
</p:dataTable>
<p:separator/>
</h:form>
</h:body>
I followed the primefaces demo as well for the bean :
public class EvaluationViewController implements Serializable {
#EJB
private SectionFacade ejbSectionFacade;
private List<Section> currentSections;
private Section currentSection;
#EJB
private UeFacade ejbUeFacade;
private List<Ue> ues;
private Ue ue;
#EJB
private OrganizedUeFacade ejbOrganizedUeFacade;
private List<OrganizedUe> organizedUes;
private OrganizedUe organizedUe;
#EJB
private CapacityFacade ejbCapacity;
private List<Capacity> capacities;
private Capacity capacity;
#PostConstruct
public void init() {
currentSections = ejbSectionFacade.findAll();
ues = new ArrayList<>();
organizedUes = new ArrayList<>();
capacities = new ArrayList<>();
}
public void onSectionSelected() {
if (currentSection != null && !currentSection.getName().equals("")) {
ues = ejbUeFacade.findBySection(currentSection);
ue = null;
capacity = null;
FacesMessage facesMessage = new FacesMessage("Sélection", currentSection.getName());
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
} else {
ues = null;
}
}
public void onUeSelected() {
if ((currentSection != null && !currentSection.getName().equals(""))
&& (ue != null && !ue.getName().equals(""))) {
organizedUes = ejbOrganizedUeFacade.findByUe(ue);
capacities = ejbCapacity.findByUe(ue);
capacity = null;
FacesMessage facesMessage = new FacesMessage("Sélection de l'UE : ", ue.getName());
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
} else {
organizedUes = null;
}
}
public void listenerCapacitiesUpdate() {
capacities = ejbCapacity.findByUe(ue);
}
The DataTable is updated and rendered but not the last oneMenu. I really don't get it. I would be very gratefull for the answer.
There are two things at hand here:
If you do not provide an explict event, then a default one is taken
You cannot add two ajax tags to the same component listening to the same event
So if in this case the default ajax event of the p:selectOneMenu is change, only the second one will be processed. Adding an explicit event other than change to the first ajax handler will make it work
Off-topic but important things you should normally do debugging issues like this:
Find the differences between the two and see and try to make them as identical as possible
See if the order plays a role by switching them
See if using a different component makes it work
I am migrating an JSP/Servlets website to JSF and am having difficulty in implementing some of the more interesting abilities of JSF. The current problem that I have attempted to resolve for several days is deleting one or more rows from a <p:dataTable>. The following code snippet defines the table:
<ui:composition template="/templates/RescueDBAdminTemplate.xhtml" ... >
<ui:define name="body">
<div id="mainContent">
<h1> Pet Information Edit </h1>
<p>
This page allows the detailed information for an animal to be inserted or edited.
</p>
<br />
<!--
~~~~ The first row contains the AIF number, and two optional hyperlinks to the History and Cage Card
~~~~ pages. Since we have at most three entries, and a layout of 4 columns, we will need a sub-table
~~~~ to evenly space out these objects.
~~~~ -->
<table class="w100pct">
<tr>
<!--
~~~~ Display the AIF_NO for the animal at the top of the page. For Reference Only.
~~~~ -->
<td class="label" align="left" >
AIF Number: #{animals.aifNo}
</td>
<td align="center"> Display History </td>
<td align="right"> Display Cage Card </td>
</tr>
</table>
<p:accordionPanel id="profile" multiple="true" activeIndex="0,1,2,3,4,5,6,7">
<p:tab title="Cage Card Information">
<h:form id="cageCardForm">
<p:panelGrid styleClass="rdbGrid w100pct">
<p:row>
<p:column styleClass="block"> Child Friendly: </p:column>
<p:column>
<p:selectOneMenu id="childFriendly" value="#{animals.isChildFriendly}">
<f:selectItem itemValue="Y" itemLabel="Yes" />
<f:selectItem itemValue="N" itemLabel="No" />
<f:selectItem itemValue="U" itemLabel="Unknown" />
<f:selectItem itemValue="O" itemLabel="Older Children Only" />
</p:selectOneMenu>
</p:column>
<p:column styleClass="block"> Dog Friendly: </p:column>
<p:column>
<p:selectOneMenu id="dogFriendly" value="#{animals.isDogFriendly}">
<f:selectItem itemValue="Y" itemLabel="Yes" />
<f:selectItem itemValue="N" itemLabel="No" />
<f:selectItem itemValue="U" itemLabel="Unknown" />
<f:selectItem itemValue="T" itemLabel="Tolerates" />
<f:selectItem itemValue="S" itemLabel="Some" />
</p:selectOneMenu>
</p:column>
</p:row>
<p:row>
<p:column styleClass="block"> Cat Friendly: </p:column>
<p:column>
<p:selectOneMenu id="catFriendly" value="#{animals.isCatFriendly}">
<f:selectItem itemValue="Y" itemLabel="Yes" />
<f:selectItem itemValue="N" itemLabel="No" />
<f:selectItem itemValue="U" itemLabel="Unknown" />
<f:selectItem itemValue="T" itemLabel="Tolerates" />
<f:selectItem itemValue="S" itemLabel="Some" />
</p:selectOneMenu>
</p:column>
<p:column styleClass="block"> Housebroken: </p:column>
<p:column>
<p:selectOneMenu id="housebroken" value="#{animals.isHousebroken}">
<f:selectItem itemValue="Y" itemLabel="Yes" />
<f:selectItem itemValue="N" itemLabel="No" />
<f:selectItem itemValue="U" itemLabel="Unknown" />
</p:selectOneMenu>
</p:column>
</p:row>
<p:row>
<p:column styleClass="block" style="text-align:top;"> Cage Card Comments: </p:column>
<p:column> <p:inputTextarea name="previousOwner" rows="11" cols="40" value="#{animals.cageCardComment}" /> </p:column>
<p:column styleClass="block" style="text-align:top;"> Lifestyle Needs: </p:column>
<p:column> <p:inputTextarea name="reasonObtained" rows="11" cols="40" value="#{animals.lifestyleNeeds}" /> </p:column>
</p:row>
</p:panelGrid>
</h:form>
</p:tab>
<p:tab title="Fees and Expenditures">
<h:form id="feesForm">
<p:panelGrid styleClass="rdbGrid w100pct">
<p:row>
<p:column styleClass="block"> Adoption Fee: </p:column>
<p:column>
<p:inputText size="16" value="#{animals.adoptionFee}" maxlength="64" />
</p:column>
<p:column styleClass="block"> Normal Costs: </p:column>
<p:column>
<p:inputText size="16" value="#{animals.costRegular}" maxlength="64" />
</p:column>
</p:row>
<p:row>
<p:column styleClass="block"> Extra Costs: </p:column>
<p:column>
<p:inputText size="16" value="${aifBean.costNonRegular}" maxlength="64" />
</p:column>
<p:column styleClass="block"> Extra Cost Description </p:column>
<p:column>
<p:inputTextarea rows="4" cols="40" value="#{animals.nonRegularDesc}" />
</p:column>
</p:row>
<p:row>
<p:column styleClass="block"> Comments </p:column>
<p:column colspan="3">
<p:inputTextarea rows="2" cols="80" value="#{animals.comments}" />
</p:column>
</p:row>
</p:panelGrid>
</h:form>
</p:tab>
<p:tab title="Medical History">
<p:dataTable styleClass="w100pct" var="current" value="#{medical.getMedHistoryByAifNo(param.AIF_NO)}">
<p:column headerText="Delete">
Delete
</p:column>
<p:column headerText="Procedure Name">
#{current.shortName}
</p:column>
<p:column headerText="Date">
#{current.treatmentDate}
</p:column>
<p:column headerText="Vet Information">
#{current.vetName} #{current.vetClinic}
</p:column>
<p:column headerText="Comments">
#{current.comments}
</p:column>
</p:dataTable>
</p:tab>
<p:tab title="Documents">
<h:form id="docListForm">
<p:dataTable id="docListTable" styleClass="w100pct" var="current" value="#{documents.currentDocList}"
paginator="true" rows="10" selection="#{documents.selectedDocs}">
<p:column selectionMode="multiple" style="width:2%" />
<p:column headerText="Date">
<h:outputText value="#{current.treatmentDate}" />
</p:column>
<p:column headerText="Document Type">
<h:outputText value="#{current.group}" converter="com.rescuedb.DocGroupName" />
</p:column>
<p:column headerText="Description">
#{current.description}
</p:column>
<f:facet name="footer">
<p:commandButton id="docListDelete" value="Delete Selected Records"
icon="ui-icon-search"
update=":#{p:component('docListTable')}"
actionListener="#{documents.deleteReference}" >
<f:param name="docNo" value="#{current.docNo}" />
<f:param name="refNo" value="#{animals.aifNo}" />
<f:param name="group" value="#{current.group}" />
</p:commandButton>
</f:facet>
</p:dataTable>
</h:form>
</p:tab>
</p:accordionPanel>
</div>
</ui:define>
</ui:composition>
The managed bean that backs this page is as follows (this is fairly preliminary code, as I am still experimenting with PrimeFaces and JSF):
package com.rescuedb.beans.managed;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import org.apache.log4j.Logger;
import com.rescuedb.Beans.DocMasterBean;
import com.rescuedb.Beans.DAO.DocMaster;
import com.rescuedb.Beans.DAO.DocXref;
import com.rescuedb.Beans.Models.DocMasterDataModel;
import com.rescuedb.Core.RescueException;
#ManagedBean(name="documents")
#ViewScoped
public class DocumentManagedBean implements Serializable
{
static final long serialVersionUID = 5L;
static Logger logger = Logger.getLogger(DocumentManagedBean.class);
private transient DocMaster docInfo; // Document Master accessor object
private transient DocXref xrfInfo; // Document Master accessor object
private String currentAifNo;
private String refNo;
private String docNo;
/**
* Contains a list of document records, wrapped in a DataModel, for the currently
* active foster animal.
*/
private DocMasterDataModel currentDocList = null;
private DocMasterBean[] selectedDocs;
public DocumentManagedBean()
{
logger.trace ("DocumentManagedBean.constructor");
try {
//
// Retrieve the URL parameter from the context.
//
FacesContext context = FacesContext.getCurrentInstance();
Map<String,String> paramMap = context.getExternalContext().getRequestParameterMap();
String paramAifNo = paramMap.get("AIF_NO");
if (paramAifNo != null) {
if (!paramAifNo.isEmpty()) {
currentAifNo = paramAifNo;
loadCurrentDocList();
}
}
} catch (Exception e) {
logger.error ("Exception caught in DocumentManagedBean() constructor :: " + e.getMessage(), e);
}
}
/**
* Initialize the bean from the database.
*/
#PostConstruct
public void initialize ()
{
logger.trace ("DocumentManagedBean.initialize");
try {
docInfo = new DocMaster();
xrfInfo = new DocXref();
} catch (Exception e) {
logger.error ("Exception in DocumentsManagedBean.initialize() : " + e.getMessage(), e);
}
}
public List<DocMasterBean> getDocList()
{
logger.trace ("DocumentManagedBean.getDocList");
return docInfo.getRecordList();
}
/**
* Retrieve the list of documents that are associated wit a specific foster animal.
* <p>
* #param aifNo
* #return
*/
public DocMasterDataModel getCurrentDocList()
{
logger.trace ("DocumentManagedBean.getCurrentDocList");
return currentDocList;
}
/**
* Load the document list for the currently active foster animal.
*/
private void loadCurrentDocList()
{
DocMaster docMaster = null;
logger.info ("DocumentManagedBean.loadCurrentDocList");
try {
docMaster = new DocMaster();
if (currentAifNo != null) {
if (!currentAifNo.isEmpty()) {
docMaster.queryByRefNo (Integer.parseInt(currentAifNo));
currentDocList = new DocMasterDataModel (docMaster.getRecordList());
logger.info ("DocumentManagedBean.loadCurrentDocList :: currentDocList reloaded, length = " + docMaster.getRecordCount());
} else {
logger.info ("DocumentManagedBean.loadCurrentDocList :: currentAifNo is empty, no records loaded.");
}
} else {
logger.info ("DocumentManagedBean.loadCurrentDocList :: currentAifNo is null, no records loaded.");
}
} catch (Exception e) {
logger.error ("Exception in DocumentsManagedBean.loadCurrentDocList() : " + e.getMessage(), e);
}
}
public void deleteReference(ActionEvent event)
{
boolean status; // Status of the update.
int refNo = 0;
int docNo = 0;
logger.info ("DocumentManagedBean.deleteReference");
try {
//
// Retrieve the parameter of the request.
//
FacesContext context = FacesContext.getCurrentInstance();
Map<String,String> paramMap = context.getExternalContext().getRequestParameterMap();
String paramDocNo = paramMap.get("docNo");
String paramRefNo = paramMap.get("refNo");
logger.info (String.format("DocumentManagedBean.deleteReference :: paramDocNo = [%s]", paramDocNo));
logger.info (String.format("DocumentManagedBean.deleteReference :: paramRefNo = [%s]", paramRefNo));
//
// Retrieve the items necessary to delete the proper records.
// The refNo parameter will only be specified when a specific cross-referenced
// record is to be deleted. If this value is missing, then the master document
// is to be deleted.
//
if (paramRefNo != null) {
try {
refNo = Integer.parseInt (paramRefNo);
this.refNo = paramRefNo;
} catch (NumberFormatException e) {
refNo = 0;
}
}
//
// The docNo has to be present. If the refNo is zero, then we will delete the
// master document. If a refNo is present, then we will delete a cross reference.
//
if (paramDocNo != null) {
try {
docNo = Integer.parseInt (paramDocNo);
this.docNo = paramDocNo;
} catch (NumberFormatException e) {
docNo = 0;
String message = String.format ("Illegal value for docNo (%d)", docNo);
logger.error(String.format("DocumentManagedBean.deleteReference :: Exception Message [%s]", message));
throw new RescueException ("DS000091", message, "DocumentsManagedBean", "deleteReference");
}
} else {
logger.error("DocumentManagedBean.deleteReference :: paramDocNo is null");
}
//
// Delete the cross reference record.
//
if (refNo != 0) {
xrfInfo = new DocXref();
status = xrfInfo.queryByCrossRef (docNo, refNo);
if (status != true) {
String message = String.format ("Error querying DOC_xref for refNo = %d, docNo = %d", refNo, docNo);
logger.error(String.format("DocumentManagedBean.deleteReference :: Exception Message [%s]", message));
throw new RescueException ("DS000092", message, "DocumentsManagedBean", "deleteReference");
} else {
status = xrfInfo.delete();
logger.warn("DocumentManagedBean.deleteReference :: Document XRef deleted");
// logger.warn("DocumentManagedBean.deleteReference :: TEST TEST TEST Document XRef not actually deleted");
if (status != true) {
String message = String.format ("Error deleting DOC_xref for refNo = %d, docNo = %d", refNo, docNo);
logger.error(String.format("DocumentManagedBean.deleteReference :: Exception Message [%s]", message));
throw new RescueException ("DS000093", message, "DocumentsManagedBean", "deleteReference");
} else {
loadCurrentDocList();
logger.error("DocumentManagedBean.deleteReference :: currentDocList reloaded");
}
}
} else {
logger.error("DocumentManagedBean.deleteReference :: refNo is 0. No Records were deleted.");
}
} catch (RescueException e) {
logger.error ("RescueException in DocumentsManagedBean.deleteReference() :: " + e.getMessage(), e);
} catch (Exception e) {
logger.error ("Exception in DocumentsManagedBean.deleteReference()", e);
}
}
public DocMaster getDocInfo()
{
logger.info ("DocumentManagedBean.getDocInfo");
return docInfo;
}
public void setDocInfo(DocMaster docInfo)
{
logger.info ("DocumentManagedBean.setDocInfo");
this.docInfo = docInfo;
}
public String getRefNo()
{
logger.info ("DocumentManagedBean.getRefNo");
return refNo;
}
public void setRefNo(String refNo)
{
logger.info ("DocumentManagedBean.setRefNo");
this.refNo = refNo;
}
public String getDocNo()
{
logger.info ("DocumentManagedBean.getDocNo");
return docNo;
}
public void setDocNo(String docNo)
{
logger.info ("DocumentManagedBean.setDocNo");
this.docNo = docNo;
}
public DocMasterBean[] getSelectedDocs()
{
logger.info ("DocumentManagedBean.getSelectedDocs");
return selectedDocs;
}
public void setSelectedDocs(DocMasterBean[] selectedDocs)
{
logger.info ("DocumentManagedBean.setSelectedDocs");
this.selectedDocs = selectedDocs;
}
}
I have tried a number of different strategies, and have read a fair number of very detailed explanations of this process in other StackOverflow threads (Thank you, BalusC!), but have still been unable to actually invoke the action listener.
My Environment is as follows:
Java 1.6
Eclipse Kepler (originally Juno)
GlassFish 3.1.2
PrimeFaces 3.5.0
From a presentation perspective, the XHTML displays correctly. The <p:dataTable> element is rendered just like the documentation and examples indicate, but when I attempt to delete a a row, the listener is never invoked.
I have tried changing the update name several times. Currently, the value of the update parameter is profile:docListForm:docListTable.
Other posts seem to indicate that there was a problem with <p:commandButton> from within a <p:accordianPanel>, but that was for a previous version of PrimeFaces (3.2).
I have tried moving the <p:commandButton> outside the <p:dataTable> and also on each row, yet the behavior does not change.
If your Listener does not trigger try this, it work fine in p:tables
<p:column id="delete" headerText="Action" width="65">
<h:commandLink value="Delete"
action="#{documents.deleteReference(current.docNo,animals.aifNo,current.group)}" ajax="false" />
</p:column>
And in your documents bean:
public void deleteReference(String docNo, String aifNo, String group)
You can actually pass the 2 string that you eventually cast as int but as Integer wrapper in the method not the primitive.
Cheers,
Thierry
Try to add ajax="false" attribute in commandbutton ,Something like this.
<p:commandButton value="Non-Ajax Submit" actionListener="#{pprBean.savePerson}"
ajax="false" />
Or use h:commandButton with ajax="false" here also .
In my application i got same issue plenty of time and i got answer few week back that issue with the page or code somewhere in the page or managed bean throwing exception or some logic going fail which is generating exception for JSF that is the main reason behind firing the event.It is JSF2 feature not to fire event if code or logic fail somewhere . May be this will help you
I have simple JSF page and simple backing bean. I have p:commandButton on the page and p:datatable. With commandButton I need to update dataTable with ajax, but it does not happens. What could be the reason?
Here is the page:
<ui:define name="content">
<h2>#{menu['management.roles.perms']}</h2>
<h:form id="form">
<p:fieldset style="border: 0px" toggleable="false" collapsed="false">
<p:tabView>
<p:tab title="#{messages['roles']}">
<p:dataTable id="dataTable" value="#{rolesBean.roles}" var="role"
editable="true" rows="10" rowKey="#{role.id}">
<p:ajax event="rowEdit" listener="#{rolesBean.onEdit}"/>
<f:facet name="footer">
<p:commandButton value="#{misc['add.role']}"
actionListener="#{rolesBean.addRole}" update="dataTable"/>
</f:facet>
<p:column headerText="#{misc['name.database']}">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{role.name}"/>
</f:facet>
<f:facet name="input">
<h:inputText value="#{role.name}"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="#{misc['date']}">
<f:facet name="output">
<h:outputText value="#{role.creationDate}">
<f:convertDateTime pattern="dd.MM.yyyy" />
</h:outputText>
</f:facet>
</p:column>
<p:column headerText="#{misc['description']}">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{role.description}"/>
</f:facet>
<f:facet name="input">
<h:inputText value="#{role.description}"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="#{messages['edit']}">
<p:rowEditor />
</p:column>
</p:dataTable>
</p:tab>
<p:tab title="#{messages['perms']}">
</p:tab>
<p:tab title="#{clients['history']}">
</p:tab>
</p:tabView>
</p:fieldset>
</h:form>
</ui:define>
And here is the code of backingBean:
#ViewScoped
#ManagedBean(name = "rolesBean")
public class RolesViewBean extends BasicViewBean<Role> {
private static final long serialVersionUID = 27377603187254821L;
#Inject
RoleDao dao;
private List<Role> roles;
#Override
protected BasicDao<Role> getDAO() {
return dao;
}
public void onEdit(RowEditEvent event){
this.entity = (Role) event.getObject();
dao.update(this.entity);
}
public void addRole(){
roles.add(new Role());
}
public List<Role> getRoles() {
roles = dao.getRoleList();
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
}
At first glance, the problem is that your addRole method modifes the "roles" list, while the getRoles (which gets called by the dataTable) resets it to whatever is saved in the database.
So your datatabe gets updated, it' just that it gets updated with the same values.
Think about that ;)
I have PrimeFaces dataTable that is been filled by a Ajax call.
When I click on a column title, to order its values, the values disappear.
<p:commandButton value="Pesquisar" actionListener="#{requestController.listRequests}" update="dataTable" />
Here is my view:
<p:dataTable id="dataTable" var="order" value="#{requestController.backing.requestsList}"
paginator="true" rows="10"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}">
<p:column sortBy="#{order.companyRequest}">
<f:facet name="header">
<h:outputText value="Pedido" />
</f:facet>
<h:outputText value="#{order.companyRequest}" />
</p:column>
<p:column sortBy="#{order.company.companyName}">
<f:facet name="header">
<h:outputText value="Cliente" />
</f:facet>
<h:outputText value="#{order.company.companyName}" />
</p:column>
<p:column sortBy="#{order.emissionDate}">
<f:facet name="header">
<h:outputText value="Data" />
</f:facet>
<h:outputText value="#{order.emissionDate}">
<f:convertDateTime pattern="dd/MM/yyyy"/>
</h:outputText>
</p:column>
<p:column sortBy="#{order.requestSituation.description}">
<f:facet name="header">
<h:outputText value="Status" />
</f:facet>
<h:outputText value="#{order.requestSituation.description}" />
</p:column>
<p:column>
<f:facet name="header">
</f:facet>
<h:form>
<h:commandLink value="Detalhes"/>
</h:form>
</p:column>
</p:dataTable>
EDIT
RequestController
#ManagedBean
#RequestScoped
public class RequestController implements Serializable
{
private RequestBacking backing;
public RequestController()
{
backing = new RequestBacking();
}
public void changeEventListener(ValueChangeEvent e)
{
backing.requestSearchType = e.getNewValue().toString();
}
public void change()
{
switch (backing.requestSearchType)
{
case "data":
backing.mask = "99/99/9999";
backing.maskSize = "10";
break;
case "cnpj":
backing.mask = " 99.999.999/9999-99";
backing.maskSize = "20";
break;
default:
backing.mask = "";
backing.maskSize = "50";
}
}
public void listRequests() throws ParseException
{
CompanyVO companyVO = new CompanyVO();
switch (backing.requestSearchType)
{
case "cnpj":
companyVO.setCnpj(backing.requestSearchValue);
break;
case "cliente":
companyVO.setCompanyName(backing.requestSearchValue);
break;
case "pedido":
backing.requestVO.setCompanyRequest(Integer.parseInt(backing.requestSearchType));
break;
}
SupplierVO supplierVO = new Support().getUserSession().getSupplier();
backing.requestVO.setEmissionDate(new Support().convertDate(backing.requestSearchValue));
backing.requestVO.setSupplier(supplierVO);
backing.requestVO.setCompany(companyVO);
backing.requestsList = new ArrayList<>(backing.getBo().getRequest(backing.requestVO));
if (backing.requestsList.isEmpty())
{
FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_WARN, "Nenhum registro encontrado!", null);
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
backing.requestsList = null;
}
}
..backing getter and setter
}
My requestsList is on my RequestBacking where I have all my getters and setters, please correct me if there is a better way of doing this, I'm using it because it leaves my controller cleaner.
public List<RequestVO> requestsList;
Apparently the value="#{requestController.backing.requestsList}" didn't return the same value as it did on the initial request. That can happen if it's a request scoped bean and/or if the requestsList is populated on every request based on a request based variable.
That's just a design mistake. Put the managed bean in the view scope and make sure that you aren't doing any business logic in a getter method. The nested class backing is also suspicious or it must be a poor naming.
See also:
Why JSF calls getters multiple times
How to choose the right bean scope?
Update in a nutshell, your bean should look something like this:
#ManagedBean
#ViewScoped
public class Orders {
private String query; // +getter +setter
private List<Order> results; // +getter (no setter required)
#EJB
private OrderService service;
public void search() {
results = service.search(query);
}
// Add/generate normal getters/setters (don't change them!)
}
and your view should look like this:
<h:form>
<p:inputText value="#{orders.query}" />
<p:commandButton value="Search" action="#{orders.search}" update=":tableForm" />
</h:form>
<h:form id="tableForm">
<p:dataTable value="#{orders.results}" var="order" ... rendered="#{not empty orders.results}">
...
</p:dataTable>
<h:outputText value="No results found" rendered="#{facesContext.postback and empty orders.results}" />
</h:form>