I am trying to integrate PrimeFaces 3.0 into my JSF 2.0 project. I've created some example code to try and get a PrimeFaces <p:dataTable>
with a delete button/link in a column for each row. I want the delete action to trigger an Ajax refresh of the table (my current code triggers a render of the enclosing form using @form).
My problem is that the PrimeFaces components do not appear to be firing events that can be handled by the core JSF <f:ajax>
tag. I am using <f:ajax>
as an Ajax Group that encloses the <p:dataTable>
as well as another command button.
If I implement this purely using core JSF elements (<h:dataTable>
, <h:commandButton>
, etc.) everything works as expected. Pardon the ugly output, but I'm not going to waste time on CSS styling for my example code.
Here is the code for the core JSF implementation page:
<h:form id="dataTableForm">
<f:ajax
listener="#{dataTableTestBean.processAjaxBehavior}"
event="action"
render="@form :messages :ajaxRenderTargetsInTemplate">
<h:panelGroup id="dataTablePanelGroup">
<h:commandLink
id="commandLinkAddRow"
value="Add Sample Row"
actionListener="#{dataTableTestBean.handleAddDataTableRow}" />
<h:commandButton
id="commandButtonAddRow"
value="Add Sample Row"
actionListener="#{dataTableTestBean.handleAddDataTableRow}" />
<sandbox:dataTableCC
id="dataTableCC"
valueList="#{dataTableTestBean.dataTableList}" />
</h:panelGroup>
</f:ajax>
<h:panelGroup rendered="#{empty dataTableTestBean.dataTableList}">
<h3>No Records To Display</h3>
</h:panelGroup>
<h:commandButton
id="commandButtonBackToStartPage"
value="#{bundle.backToStartPage}"
action="start"
immediate="true" />
</h:form>
Here is the code for the core JSF implementation CC:
<composite:implementation>
<h:dataTable
id="theDataTable"
rendered="#{not empty cc.attrs.valueList}"
value="#{cc.attrs.valueList}"
var="row"
emptyMessage="#{bundle.dataTableEmptyMessage}">
<f:facet name="header">#{bundle.dataTableHeader}</f:facet>
<h:column id="columnDeleteButton">
<h:commandLink
id="commandLinkDelete"
value="Delete"
action="#{dataTableTestBean.actionDeleteDataTableRow(row)}" />
</h:column>
<h:column>
<h:commandButton
alt="#{bundle.delete}"
image="#{resource['images/onebit_33_24x24.gif']}"
action="#{dataTableTestBean.actionDeleteDataTableRow(row)}" />
</h:column>
<h:column sortBy="#{row.name}">
<f:facet name="header">
#{bundle.columnHeaderName}
</f:facet>
<h:outputText value="#{row.name}" />
</h:column>
<h:column sortBy="#{row.rank}">
<f:facet name="header">
#{bundle.columnHeaderRank}
</f:facet>
<h:outputText value="#{row.rank}" />
<f:facet name="footer">
#{bundle.columnFooterRank}
</f:facet>
</h:column>
<h:column sortBy="#{row.serialNumber}">
<f:facet name="header">
#{bundle.columnHeaderSerialNumber}
</f:facet>
<h:outputText value="#{row.serialNumber}" />
<f:facet name="footer">
#{bundle.columnFooterSerialNumber}
</f:facet>
</h:column>
<f:facet name="footer">#{bundle.dataTableFooter}</f:facet>
</h:dataTable>
</composite:implementation>
The core JSF implementation will nicely fire the Ajax events and do the Partial Page Rendering, part of which is the render of an <h:messages>
that confirms the event was processed successfully.
When I replace the <h:dataTable>
with a <p:dataTable>
, no problem. However, if I replace the <h:commandButton>
and <h:commandLink>
with <p:commandButton>
and <p:commandLink>
, the Ajax events are not making it to the <f:ajax>
Ajax Group element. The record delete and insert operations do actually happen on the server, but the page is never refreshed. I will appear to the user that nothing happened. If you click the browser Refresh button, you will see that the operation did indeed happen. If you click the core JSF command button or command link, everything works. The PrimesFaces table renders and even the PrimeFaces "growl" popups are displayed as expected.
Here is a screenshot of the PrimeFaces implementation that has the problem. Again, pardon the ugliness of the buttons and links.
First, the page:
<p:growl id="growl" showSummary="false" showDetail="true" />
<h:form id="dataTableForm" styleClass="ui-widget">
<f:ajax
listener="#{dataTableTestBean.processAjaxBehavior}"
event="action"
render="@form :growl :ajaxRenderTargetsInTemplate">
<h:panelGroup id="dataTablePanelGroup">
<p:commandLink
id="pfCommandLinkAddRow"
value="Add Sample Row (pf)"
ajax="true"
actionListener="#{dataTableTestBean.handleAddDataTableRow}" />
<p:commandButton
id="pfCommandButtonAddRow"
value="Add Sample Row (pf)"
ajax="true"
actionListener="#{dataTableTestBean.handleAddDataTableRow}" />
<h:commandLink
id="hCommandLinkAddRow"
value="Add Sample Row (h)"
actionListener="#{dataTableTestBean.handleAddDataTableRow}" />
<h:commandButton
id="hCommandButtonAddRow"
value="Add Sample Row (h)"
actionListener="#{dataTableTestBean.handleAddDataTableRow}" />
<sandbox:primeFacesDataTableCC
id="dataTableCC"
valueList="#{dataTableTestBean.dataTableList}" />
</h:panelGroup>
</f:ajax>
<h:panelGroup rendered="#{empty dataTableTestBean.dataTableList}">
<h3>No Records To Display</h3>
</h:panelGroup>
<h:commandButton
id="commandButtonBackToStartPage"
value="#{bundle.backToStartPage}"
action="start"
immediate="true" />
</h:form>
and the CC:
<composite:implementation>
<p:dataTable
id="theDataTable"
rendered="#{not empty cc.attrs.valueList}"
value="#{cc.attrs.valueList}"
var="row"
emptyMessage="#{bundle.dataTableEmptyMessage}">
<f:facet name="header">#{bundle.dataTableHeader}</f:facet>
<p:column id="columnpclDelete">
<p:commandLink
id="pclDelete"
value="Delete (pf)"
action="#{dataTableTestBean.actionDeleteDataTableRow(row)}" />
</p:column>
<p:column id="columnpcbDeleteIconOnly">
<p:commandButton
id="pcbDeleteIconOnly"
ajax="true"
global="true"
alt="#{bundle.delete}"
image="ui-icon ui-icon-trash"
action="#{dataTableTestBean.actionDeleteDataTableRow(row)}" />
</p:column>
<p:column id="columnhclDelete">
<h:commandLink
id="hclDelete"
value="Delete (h)"
action="#{dataTableTestBean.actionDeleteDataTableRow(row)}" />
</p:column>
<p:column id="columnhcbDeleteWithImage">
<h:commandButton
id="hcbDeleteWithImage"
alt="#{bundle.delete}"
image="#{resource['images/onebit_33_24x24.gif']}"
action="#{dataTableTestBean.actionDeleteDataTableRow(row)}" />
</p:column>
<p:column id="columnName" sortBy="#{row.name}">
<f:facet name="header">
#{bundle.columnHeaderName}
</f:facet>
<h:outputText value="#{row.name}" />
</p:column>
<p:column id="columnRank" sortBy="#{row.rank}">
<f:facet name="header">
#{bundle.columnHeaderRank}
</f:facet>
<h:outputText value="#{row.rank}" />
<f:facet name="footer">
#{bundle.columnFooterRank}
</f:facet>
</p:column>
<p:column id="serialNumber" sortBy="#{row.serialNumber}">
<f:facet name="header">
#{bundle.columnHeaderSerialNumber}
</f:facet>
<h:outputText value="#{row.serialNumber}" />
<f:facet name="footer">
#{bundle.columnFooterSerialNumber}
</f:facet>
</p:column>
<f:facet name="footer">#{bundle.dataTableFooter}</f:facet>
</p:dataTable>
</composite:implementation>
Where have I gone wrong? Everything works correctly except for the Ajax events from the PrimeFaces components.