I have a PrimeFaces p:dataTable
and enabled lazy loading by implementing a LazyDataModel
.
The dataTable holds search results, so when doing a search request the search service only retrieves the required (paginating) data. That works fine.
When doing a ajax request with p:commandButton
:
<p:commandButton id="searchCmdBtn" value="Search" action="#{searchBean.search}"
update=":resultForm:resultList :filterForm:filterMenu :resultForm:messages"
ajax="true" />
the dataTable gets updated properly, but not the filterMenu in the filterForm (differnt forms, bcz using p:layout
).
The filterMenu is one request behind. Which means when I hit search button again, the filterMenu gets updated with t only gets updated after the 2nd ajax request
Bean
@ManagedBean
@ViewScoped
public class SearchBean implements Serializable {
private LazyDataModel<Entity> lazyDataModel;
private MenuModel filterMenuModel = new DefaultMenuModel();
private SearchResult searchResult = null;
public void search() {
// lazy call
getLazyDataModel();
if (searchResult != null) {
buildFilterMenu(searchResult);
}
}
private void initializeDataModel() {
lazyDataModel = new LazyDataModel<Entity>() {
private static final long serialVersionUID = 1L;
@Override
public List<Entity> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, String> filters) {
// handling sorting and filtering
// get search results
try {
setSearchResult(searchService.getEntities(queryText, selectedQueryOperand, getFilterOptions(), first, (first + pageSize), multiSortMeta));
} catch (Exception e) {
// handle exception
}
if (searchResult == null) {
return null;
}
List<Entity> resultEntities = searchResult.getResultEntities();
// total count
this.setRowCount((int) searchResult.getTotalSize());
return resultEntities;
}
// other override-methods
};
}
public void buildFilterMenu() {
// builds the filterMenu depending on searchResults
}
// getters and setters
public LazyDataModel<Entity> getLazyDataModel() {
if (lazyDataModel == null) {
initializeDataModel();
}
return lazyDataModel;
}
}
filters.xhtml
<ui:composition 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"
xmlns:fn="http://java.sun.com/jsp/jstl/functions">
<p:panelMenu id="filterMenu" model="#{searchBean.filterMenuModel}" />
</ui:composition>
After searching the PF forum I found the root cause:
The dataTable Lazy load() method is invoked during render response phase
To know about the phases, read this tutorial on JSF lifecycle from BalusC
Solutions for displaying messages (e.g: p:messages
or p:growl
):
Update message component with PrimeFaces RequestContext
RequestContext.getCurrentInstance().update(":growlOrMsgID");
This will not work because at that time it's too late to add additional components to update.
use dataTable attribute errorMessage
No attribute found with this name for dataTable
Put the p:messages or p:growl below the p:dataTable
Worked for me
Use PF execute method of RequestContext
The RequestContext#execute() executes a javascript after current ajax request is completed.
Worked for me
See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With