JSF, RichFaces, pagination

I know that there are quite a few posts about JSF paginatin, but none of them satisfied me.

To break up fairly large data into pages, I was going to use the RichFaces data scrolling component.

This seemed to be suitable for this, but it looks like it is an β€œartificial” pagination.

I do not like that it downloads all the data, and then just displays part of it. At least it seems so. Correct me if I am wrong.

Rich faces have nice demos, but for some reason they skip the bean definitions - only xhtml. I saw some mention of ExtendedDataModel, but the only example I found did not impress me. Why did I assume that 5 screen codes just displays a subset of the data?

Honestly, such a simple question like pagination turned out to be very difficult in JSF, and I really don't understand why.

So my questions are: 1. is it possible to load only one data page in Richfaces 2. without saving it in the session (I mean actual data that does not display the current current page, etc.)

I'm only interested in the rich lib interface that already uses it in my project, and there is no need to add a dependency on somethin else

thanx in advance

+6
source share
1 answer

After a conversation on the RichFaces forum, the following solution appeared (thanx to Brendan Healey):

RichLazyDataModel.java

/** * Extended data model * @author Brendan Healey */ public abstract class RichLazyDataModel<T> extends ExtendedDataModel<T> { private SequenceRange cachedRange; private Integer cachedRowCount; private List<T> cachedList; private Object rowKey; public abstract List<T> getDataList(int firstRow, int numRows); public abstract Object getKey(T t); public abstract int getTotalCount(); @Override public void walk(FacesContext ctx, DataVisitor dv, Range range, Object argument) { SequenceRange sr = (SequenceRange) range; if (cachedList == null || !equalRanges(cachedRange, sr)) { cachedList = getDataList(sr.getFirstRow(), sr.getRows()); cachedRange = sr; } for (T t : cachedList) { if (getKey(t) == null) { /* * the 2nd param is used to build the client id of the table * row, ie mytable:234:inputname, so don't let it be null. */ throw new IllegalStateException("found null key"); } dv.process(ctx, getKey(t), argument); } } /* * The rowKey is the id from getKey, presumably obtained from * dv.process(...). */ @Override public void setRowKey(Object rowKey) { this.rowKey = rowKey; } @Override public Object getRowKey() { return rowKey; } @Override public boolean isRowAvailable() { return (getRowData() != null); } @Override public int getRowCount() { if (cachedRowCount == null) { cachedRowCount = getTotalCount(); } return cachedRowCount; } @Override public T getRowData() { for (T t : cachedList) { if (getKey(t).equals(this.getRowKey())) { return t; } } return null; } protected static boolean equalRanges(SequenceRange range1, SequenceRange range2) { if (range1 == null || range2 == null) { return range1 == null && range2 == null; } else { return range1.getFirstRow() == range2.getFirstRow() && range1.getRows() == range2.getRows(); } } /* * get/setRowIndex are used when doing multiple select in an * extendedDataTable, apparently. Not tested. Actually, the get method is * used when using iterationStatusVar="it" & #{it.index}. */ @Override public int getRowIndex() { if (cachedList != null) { ListIterator<T> it = cachedList.listIterator(); while (it.hasNext()) { T t = it.next(); if (getKey(t).equals(this.getRowKey())) { return it.previousIndex() + cachedRange.getFirstRow(); } } } return -1; } @Override public void setRowIndex(int rowIndex) { int upperBound = cachedRange.getFirstRow() + cachedRange.getRows(); if (rowIndex >= cachedRange.getFirstRow() && rowIndex < upperBound) { int index = rowIndex % cachedRange.getRows(); T t = cachedList.get(index); setRowKey(getKey(t)); } } @Override public Object getWrappedData() { throw new UnsupportedOperationException("Not supported yet."); } @Override public void setWrappedData(Object data) { throw new UnsupportedOperationException("Not supported yet."); } public List<T> getCachedList() { return cachedList; } 

}

ListState.java

 /** * Holds list state */ public class ListState implements Serializable { private int page; private Map<String, Serializable> searchCriteria = new HashMap<String, Serializable>(); public int getPage() { return page; } public void setPage(int page) { this.page = page; } public Map<String,Serializable> getSearchCriteria() { return searchCriteria; } 

}

CardsBean.java

 @ManagedBean(name="cardsBean") public class CardsBean { @ManagedProperty("#{cardService}") private CardService cardService; private ListState state; private RichLazyDataModel<Card> cardsModel = new RichLazyDataModel<Card>() { @Override public List<Card> getDataList(int firstRow, int numRows) { MyUserDetails user = SecurityUtils.getCurrentUser(); return cardService.findUserCards(user.getUser(), firstRow, numRows, state.getSearchCriteria()); } @Override public Object getKey(Card card) { return card.getId(); } @Override public int getTotalCount() { MyUserDetails user = SecurityUtils.getCurrentUser(); return cardService.countUserCards(user.getUser(), state.getSearchCriteria()); } }; public RichLazyDataModel<Card> getCards() { return cardsModel; } public String getSearchString() { return (String)state.getSearchCriteria().get("searchString"); } public int getCurrentPage() { return state.getPage(); } public void setCurrentPage(int page) { state.setPage(page); } public void setSearchString(String searchString) { state.getSearchCriteria().put("searchString", searchString); } public void setCardService(CardService cardService) { this.cardService = cardService; } public boolean isPinned() { return Boolean.TRUE.equals(state.getSearchCriteria().get("pinned")); } public void setPinned(boolean pinned) { state.getSearchCriteria().put("pinned", pinned); } public void togglePinned() { setPinned(!isPinned()); } @PostConstruct public void init() { state = getFromSession("cardsList", null); if (state == null) { state = new ListState(); storeInSession("cardsList", state); } } public <T extends Serializable> T getFromSession(String name, T defaultValue) { T ret = (T) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(name); if (ret == null) { ret = defaultValue; } return ret; } public void storeInSession(String name, Serializable obj) { FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(name, obj); } } 

cards.xhtml (partial)

 ... <h:form> <rich:dataGrid value="#{cardsBean.cards}" var="card" columns="2" elements="20" first="#{cardsBean.currentPage}" style="margin:0 auto;width:70em" id="cardsTable"> <f:facet name="header"> <h:inputText value="#{cardsBean.searchString}"> <a4j:ajax event="keyup" render=" cardsTable@body , cardsTable@footer "> <a4j:attachQueue requestDelay="700" ignoreDupResponses="true" /> </a4j:ajax> </h:inputText> </f:facet> <rich:panel id="cd"> <ui:include src="WEB-INF/parts/card.xhtml"> <ui:param name="card" value="#{card}"/> </ui:include> </rich:panel> <f:facet name="footer"> <rich:dataScroller page="#{cardsBean.currentPage}" /> </f:facet> </rich:dataGrid> </h:form> ... 
+4
source

Source: https://habr.com/ru/post/922744/


All Articles