Eti*_*sne 5 jsf lazy-loading datascroller primefaces jsf-2.2
延迟加载Primefaces Datascroller组件时遇到问题。
我有一个jsf页面,该页面应在页面加载时显示10个事件。如果用户想查看更多内容,则可以单击更多按钮以加载并显示10个下一个事件。对于每个事件行,都有一个可用于显示事件详细信息的链接。
<h:form id="mainForm" >
<p:dataScroller value="#{backing.lazyModel}" var="event" lazy="true" chunkSize="10" rowIndexVar="index">
#{event.name}
<p:commandLink class="view-trigger"
value="View Event Details"
actionListener="#{backing.initViewEventDetails(index, event)}"/>
<f:facet name="loader">
<p:outputPanel
visible="#{backing.lazyModel.rowCount gt 10}"
rendered="#{backing.lazyModel.rowCount gt 10}">
<p:commandLink value="More" />
</p:outputPanel>
</f:facet>
</p:dataScroller>
</h:form>
Run Code Online (Sandbox Code Playgroud)
初始搜索工作正常,也就是说,当我单击“查看事件详细信息”链接时,将调用后备bean,并且看到接收到的索引和事件与我单击的行相对应。
但是,一旦加载下一个包含1个额外事件的块,页面将显示11个事件,但是单击“查看事件详细信息”链接将发送适当的索引,但不会发送适当的事件。例如,如果我单击索引0处的事件,那么我将获得索引10处的事件,如果我单击索引1处的事件,将不会调用我的支持bean。
当我单击“更多”按钮时,数据滚动器似乎忘记了最后10个事件,但我的惰性数据模型仍然记得。
支持豆:
@ManagedBean(name="backing")
@ViewScoped
public class DataScrollerBacking implements Serializable {
private static final long serialVersionUID = 4012320411042043677L;
private static final Logger LOGGER = Logger.getLogger(DataScrollerBacking.class);
@ManagedProperty("#{settings.dataSource}")
private String dataSource;
private WebEventDAO webEventDAO;
private LazyDataModel<Event> lazyModel;
@PostConstruct
public void init() {
webEventDAO = CommonDAOFactory.getInstance(dataSource).getWebEventDAO();
search();
}
public void search() {
DateTime start = new DateTime(2014, 1, 1, 0, 0 ,0);
final Date startDate = start.toDate();
final Date endDate = start.plus(Years.ONE.toPeriod()).minus(Seconds.ONE.toPeriod()).toDate();
lazyModel = new LazyDataModel<Event>() {
private static final long serialVersionUID = 1231902031619933635L;
private LinkedHashSet<Event> eventCache; // Ordered set of all retrieved events so far.
// I'm using a set because the load method is called twice on page load (any idea why???) and I don't want duplicates in my cache.
@Override
public List<Event> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
List<Event> events = new ArrayList<Event>(10);
try {
if(eventCache == null){
int count = webEventDAO.getSearchByPeriodRaceTypeAndRaceStatusForCompanyCount(Collections.singletonList(1), startDate, endDate, null, null);
this.setRowCount(count);
eventCache = new LinkedHashSet<Event>(count);
}
events = webEventDAO.searchByPeriodRaceTypeAndRaceStatusForCompany(Collections.singletonList(1), startDate, endDate, null, null, true, first, pageSize);
eventCache.addAll(events);
} catch (DAOException e) {
LOGGER.error("An error occurred while retrieving events.", e);
}
return events;
}
};
}
public void initViewEventDetails(Integer index, Event event){
LOGGER.info("index=" + index + " eventname=" + event.getName());
}
public String getDataSource() {
return dataSource;
}
public void setDataSource(String dataSource) {
this.dataSource = dataSource;
}
public LazyDataModel<Event> getLazyModel() {
return lazyModel;
}
public void setLazyModel(LazyDataModel<Event> lazyModel) {
this.lazyModel = lazyModel;
}}
Run Code Online (Sandbox Code Playgroud)
由于页面显示正确的信息并且接收到的索引始终有效,所以我当前的解决方法是按索引在惰性数据模型中获取事件。
但是,我想了解为什么收到的事件不是我单击的事件。
我是在做错什么,还是这就是滚动条的实现方式?
在Mojarra 2.2,Tomcat 7,Primefaces 5,Omnifaces 1.8上运行
我终于有时间花在这个问题上并找到了解决方法。这是一个黑客,所以也许正确的解决方案是使用不同的组件或创建我自己的组件。
当将 DataScroller 与 LazyDataModel 一起使用时,似乎会出现 Primefaces DataScroller 的限制。该组件似乎不是为执行此操作而设计的。
为了避免这个问题,我实现了自己的延迟加载,除了新添加的元素之外,还返回相同的列表实例。
这是我之前的示例,经过修改以实现这种新的延迟加载模式:
html页面:
<h:form id="mainForm" >
<p:dataScroller value="#{backing.events}" var="event" rowIndexVar="index">
#{event.name}
<p:commandLink class="view-trigger"
value="View Event Details"
action="#{backing.initViewEventDetails(index, event)}"/>
<f:facet name="loader"><h:outputText value=""/></f:facet>
</p:dataScroller>
<p:commandLink value="More" process="@form" update="@form"
action="#{backing.loadMore()}"
visible="#{backing.totalCount gt backing.events.size()}"
rendered="#{backing.totalCount gt backing.events.size()}"/>
</h:form>
Run Code Online (Sandbox Code Playgroud)
DataScroller 不再具有lazy="true"、chunkSize="10",使用名为events 的列表作为值,并声明一个空的加载器facet(以避免在到达列表底部时自动加载更多内容)。我使用了一个 commandLink 来调用 backing.loadMore() 并更新表单以替换加载器方面。
支持豆:
@Named("backing")
@ViewScoped
public class DataScrollerBacking implements Serializable {
private static final long serialVersionUID = 4012320411042043677L;
private static final Logger LOGGER = Logger.getLogger(DataScrollerBacking.class);
private static final Integer CHUNK_SIZE = 10;
@DataSource
@Inject
private String dataSource;
private WebEventDAO webEventDAO;
private List<Event> events;
private Integer totalCount;
private Date startDate;
private Date endDate;
@PostConstruct
public void init() {
webEventDAO = CommonDAOFactory.getInstance(dataSource).getWebEventDAO();
search();
}
public void search() {
DateTime start = new DateTime(2014, 1, 1, 0, 0 ,0);
startDate = start.toDate();
endDate = start.plus(Years.ONE.toPeriod()).minus(Seconds.ONE.toPeriod()).toDate();
try {
totalCount = webEventDAO.getSearchByPeriodRaceTypeAndRaceStatusForCompanyCount(Collections.singletonList(1), startDate, endDate, null, null);
events = new ArrayList<Event>(totalCount);
loadMore();
} catch (DAOException e) {
LOGGER.error("An error occurred while retrieving events.", e);
}
}
public void loadMore() {
List<Event> newEvents = new ArrayList<Event>(CHUNK_SIZE);
try {
newEvents = webEventDAO.searchByPeriodRaceTypeAndRaceStatusForCompany(Collections.singletonList(1), startDate, endDate, null, null, true, events.size(), CHUNK_SIZE);
events.addAll(newEvents);
} catch (DAOException e) {
LOGGER.error("An error occurred while retrieving events.", e);
}
}
public void initViewEventDetails(Integer index, Event event){
LOGGER.info("index=" + index + " eventname=" + event.getName());
}
public String getDataSource() {
return dataSource;
}
public void setDataSource(String dataSource) {
this.dataSource = dataSource;
}
public List<Event> getEvents() {
return events;
}
public void setEvents(List<Event> events) {
this.events = events;
}
public Integer getTotalCount() {
return totalCount;
}
public void setTotalCount(Integer totalCount) {
this.totalCount = totalCount;
}}
Run Code Online (Sandbox Code Playgroud)
在支持 bean 中,search 方法计算事件总数,保存该信息并调用 loadMore() 来加载事件列表中的前 10 个事件。
单击“更多”按钮时,将再次调用 loadMore(),并将接下来的 10 个事件附加到事件列表的末尾。
现在,当我单击新加载的元素时,commandLink 会使用正确的值调用支持 bean。