Rendering JSF / PrimeFaces components based on the number of rows returned by PrimeFaces LazyDataModel <T>
I need to render some components based on the number of rows returned by PrimeFaces LazyDataModel<T>
.
For example, a <p:panelGrid>
should only display when the corresponding lazy data model returns at least one row.
<p:panelGrid rendered=#{bean.rowCount gt 0}>
...
...
...
</p:panelGrid>
Given below <p:dataList>
, which is lazy loaded.
<p:dataList var="row"
value="#{bean}"
first="0"
rows="10"
paginator="true"
lazy="true">
...
...
...
<p:dataList>
bean is pretty common:
@Named
@ViewScoped
public class Bean extends LazyDataModel<Entity> implements Serializable
{
@Inject
private BeanService service;
private static final long serialVersionUID = 1L;
@Override
public List<Entity> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters)
{
setRowCount(service.rowCount());
return service.getList(first, pageSize);
}
}
This <p:panelGrid>
one will no longer be displayed because the lazy data model is not available when the attribute is being processed rendered
<p:panelGrid>
.
The right thing would happen if the order as <p:panelGrid>
well as <p:dataList>
replaced, but it is a problem of design and can not be changed his mind.
This one <p:dataList>
contains a complex list of preview data (combined with <p:dataTable>
, <p:panelGrid>
and some others), which is then exported to an MS-Excel workbook and the file is loaded.
The list of reporting data (stored in <p:dataList>
) depends on several (customizable) filters consisting of <p:inputText>
, <p:selectOneMenu>
etc. The AJAX list is updated based on the filter values ββ/ events.
The list can be empty at any time depending on the filter values. Anyway, if <p:dataList>
empty, <p:panelGrid>
shouldn't be displayed ( <p:panelGrid>
- just a simple example. There are other components as well).
How can such components be displayed based on the number of rows returned LazyDataModel<T>
(ultimately from the linked database) without any additional overhead of running additional JPA queries to count the number of rows that can be returned based on filter values ββ(when there are already very complex / expensive posts, JPA Requirements Queries are done)?
source to share
The problem with the code has to do with how you defined the model. because of the Bean class you have defined, the model line number will not be set unless called<p:dataList>
the best I can suggest is to have a Bean and have a model inside it. something like that:
public class MainBean {
private SERVICE service;
private SEARCHOBJECT searchObject;
private BaseListDataModel<LISTMODEL> dataModel = new BaseListDataModel<LM>() {
@Override
public List<LM> load(int first,
int pageSize,
String sortField,
SortOrder sortOrder,
Map<String, String> filters) {
List<LM> result = new ArrayList<LM>();
try {
searchObject.setStartIndex(first);//this is used for my own business, you can handle the paging in some other way
searchObject.setPageSize(pageSize);//this is used for my own business, you can handle the paging in some other way
result = getService().search(searchObject);
int rowCount = searchObject.getTotalRecordCount();
this.setRowCount(rowCount);
} catch (BusinessException ex) {
log.error(ex.getMessage(), ex);
saveError(ex);
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
saveError(new UnknownSystemException(ex));
}
return result;
}
};
...
}
I hope this is helpful.
source to share
Example with list and datatable. There is no ajax event for the "change data" table. But when you do any kind of filter, sort or other update of just the table, you do it with ajax. This way you can track the ajax call and when the ajax call happens you can update your list. Here's a working code (trivial example):
please note this is not a command button to update the top list, you can change the datatable with any other ajax command and still work
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:pe="http://primefaces.org/ui/extensions"
xmlns:p="http://primefaces.org/ui" >
<pe:head title="PrimeFaces Extensions - ShowCase">
<f:facet name="first">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</f:facet>
</pe:head>
<f:view>
<h:form>
<h:panelGrid id="pvis" >
<p:dataList value="#{modelBean.data2}" var="d" rendered="#{ modelBean.data.size() > 0}" >
#{d}|
</p:dataList>
</h:panelGrid>
<p:remoteCommand name="updatelist" update="pvis" />
<p:ajaxStatus onsuccess="updatelist();" />
<p:dataTable value="#{modelBean.data}" var="d" id="table" >
<p:remoteCommand update="pvis" autoRun="true" immediate="true" />
<p:column headerText="Value" >
<p:outputLabel value="#{d}" />
</p:column>
</p:dataTable>
<p:commandButton action="#{modelBean.addRandomData()}" update="table" value="Populate" />
</h:form>
</f:view>
</html>
And the managed bean:
package com.example.stackoverflow;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@Named
@SessionScoped
public class ModelBean implements Serializable {
private List<String> data = new ArrayList<String>();
private List<String> data2 = new ArrayList<String>();
public List<String> getData() {
return data;
}
public void setData(List<String> data) {
this.data = data;
}
public List<String> getData2() {
return data2;
}
public void setData2(List<String> data2) {
this.data2 = data2;
}
@PostConstruct
public void init() {
for (int i = 0;i < 10;i++) {
Random random = new Random();
data2.add("value:"+random.nextInt());
}
}
public void addRandomData() {
for (int i = 0;i < 10;i++) {
Random random = new Random();
data.add("value:"+random.nextInt());
}
}
}
Based on your comment:
I still haven't found a way. Data tables are not suitable for reporting when a list of reports needs to be generated in a row
I add the following solution:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:pe="http://primefaces.org/ui/extensions"
xmlns:p="http://primefaces.org/ui" >
<pe:head title="PrimeFaces Extensions - ShowCase">
<f:facet name="first">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</f:facet>
</pe:head>
<f:view>
<h:form>
<p:outputPanel deferred="true" deferredMode="load" >
<p:panelGrid rendered="#{modelBean.rowCount > 0}" columns="1" >
Show me only if Lazy Model has row
</p:panelGrid>
</p:outputPanel>
<p:dataList value="#{modelBean}" lazy="true" var="d" type="unordered" itemType="none" paginator="true" rows="10" styleClass="paginated" >
<f:facet name="header">
Base list
</f:facet>
#{d}
</p:dataList>
</h:form>
</f:view>
</html>
and the lazy model:
@Named
@SessionScoped
public class ModelBean extends LazyDataModel<String> implements Serializable {
private List<String> data = new ArrayList<String>();
private List<String> data2 = new ArrayList<String>();
public List<String> getData() {
return data;
}
public void setData(List<String> data) {
this.data = data;
}
public List<String> getData2() {
return data2;
}
public void setData2(List<String> data2) {
this.data2 = data2;
}
@PostConstruct
public void init() {
for (int i = 0;i < 10;i++) {
Random random = new Random();
data2.add("value:"+random.nextInt());
}
}
/*public void addRandomData() {
for (int i = 0;i < 10;i++) {
Random random = new Random();
data.add("value:"+random.nextInt());
}
}*/
@Override
public List<String> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, Object> filters) {
data = new ArrayList<String>();
for (int i = 0;i < pageSize;i++) {
Random random = new Random();
data.add("value:"+random.nextInt());
}
setRowCount(100);
return data;
}
@Override
public List<String> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
data = new ArrayList<String>();
for (int i = 0;i < pageSize;i++) {
Random random = new Random();
data.add("value:"+random.nextInt());
}
setRowCount(100);
return data;
}
}
Note the lazy load of optional rendering (using the output pane).
Another solution would be to run a remote command to refresh the first panel at the end of the page.
Note. To make visible rendering false you need to update the parent of this element
source to share