I recently ran into a problem in JSF with the rich:dataScroller component. Basically, the dataScroller sets an attribute in its associated dataTable component to define which record it should start with. This allows for a simple pagination mechanism. If the dataTable is set to display 10 rows at a time, and it is supposed to start at index 0, then it shows the first page. When the page is advanced, the dataScroller tells the dataTable to start at index 10.
The problem arises when the dataTable is set to start at record n, and the model that it represents changes so that there are less than n records to display. In this situation, you’re suddenly seeing a page for which there are no records to see. You have to page back until you get to the “real” last page. As you can guess, this would probably be quite confusing to the end user.
A bug is logged for this defect here, and a workaround using Seam is described in a link from that URL. Unfortunately, I’m not using Seam and that solution doesn’t work for me. Another user proposed a workaround using a Phase-Listener. That solution did work for me, and I’ll post the details below. Hopefully, this will be useful to someone. If anyone has suggestions for improvements, please comment!
public class RenderResponsePhaseListener implements PhaseListener {
private PhaseId phase = PhaseId.RENDER_RESPONSE;
public void beforePhase(PhaseEvent e)
{
//This is where we want to handle the pagination issue
refreshUIDataFirstIndex();
}
public void afterPhase(PhaseEvent e) {
}
public void setPhase(PhaseId phase) {
this.phase = phase;
}
public PhaseId getPhaseId() {
return phase;
}
/**
* Handles the pagination issue
*/
private void refreshUIDataFirstIndex() {
ArrayList<UIData> allUIDataComponents = Util.getAllRenderedUIDataComponents();
for(UIData current : allUIDataComponents) {
if(current.getFirst() > current.getRowCount()) {
current.setFirst(0);
}
}
}
}
public class Util {
/**
* Gets the UIViewRoot
* @return
*/
public static UIViewRoot getUIViewRoot() {
return FacesContext.getCurrentInstance().getViewRoot();
}
/**
* Gets all rendered UIData components in the UIViewRoot
* @return
*/
public static ArrayList<UIData> getAllRenderedUIDataComponents() {
return getRenderedUIDataComponents(getUIViewRoot());
}
/**
* Gets all rendered UIData components in the UIComponent
*/
private static ArrayList<UIData> getRenderedUIDataComponents(UIComponent currentComponent) {
ArrayList<UIData> allRenderedUIDataComponents = new ArrayList<UIData>();
if(currentComponent instanceof UIData) {
allRenderedUIDataComponents.add((UIData)currentComponent);
} else {
Iterator componentIterator = currentComponent.getFacetsAndChildren();
while(componentIterator.hasNext()) {
UIComponent nextComponent = (UIComponent)componentIterator.next();
if(nextComponent.isRendered()){
allRenderedUIDataComponents.addAll(getRenderedUIDataComponents(nextComponent));
}
}
}
return allRenderedUIDataComponents;
}
}