t:datatable, t:datascroller and resetting them
NERD ALERT
The tomahawk datatable & datascroller are a very powerful combination to quickly and easily create data grids and a paginator with it. There is however a small problem with it.
When you change the datamodel attached to the datatabe. The scroller will not pick this up. It is a known problem with at least jsf 1.1. I found a lot of almost working solutions on the internet (google is your friend) but I found them all too convoluted. But they all revolve around forcing the UIData component, the datamodel base class, to be reset to the first record. One solution that came close was actually a phaselistener that had to be triggered.
So I asked myself "when does the datamodel change?", the answer is easy. Only when I change the model, does the model change. So I know when to reset the UIData.
The UIData can only found by searching for it in the
FacesContext.getCurrentInstance().getViewRoot() From there you can search for the id you gave the datatable:
<t:dataTable newspaperColumns="4" var="pic"In the above example the id is set to "data". UIViewRoot extends ultimately UIComponent, just like UIData. UIComponent has a great method called Iterator getFacetsAndChildren. Using this Iterator the tree of the view can be traversed and the UIData can be found:
columnClasses="imagetd, imagetd, imagetd, imagetd"
id="data"
rows="16" width="100%" preserveDataModel="false"
value="#{categoryBean.pictures}">
<t:column>
<h:commandLink action="#{categoryBean.detail}">
<h:graphicImage value="/thumbnail/#{pic.id}" />
<f:setPropertyActionListener value="#{pic.id}"
target="#{categoryBean.imageid}" />
</h:commandLink>
</t:column>
</t:dataTable>
<t:dataScroller id="scroll_1" renderFacetsIfSinglePage="false"
for="data" fastStep="5" pageCountVar="pageCount"
pageIndexVar="pageIndex"
styleClass="scroller" paginator="true"
paginatorMaxPages="9" paginatorTableClass="paginator"
paginatorActiveColumnStyle="font-weight:bold;" immediate="true">
<f:facet name="first"><<</f:facet>
<f:facet name="last">>> </f:facet>
<f:facet name="previous">< </f:facet>
<f:facet name="next">> </f:facet>
</t:dataScroller>
@SuppressWarnings("unchecked")
private static UIData findId(UIComponent component, String id) {
boolean done = false;
UIData data = null;
Iterator<UIComponent> iter = component.getFacetsAndChildren();
while (iter.hasNext() && !done) {
UIComponent c = iter.next();
if (c instanceof UIData && c.getId().equals(id)) {
data = (UIData) c;
done = true;
} else {
data = findId(c, id);
if (data != null)
done = true;
}
}
return data;
}
Once you have the UIData component you can call getFirst(0) methode on it to reset it. The datascroller will pick this up and all is well again.
The complete code for this can be downloaded here