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
Re: t:datatable, t:datascroller and resetting them
Long time no see ! -Everything fine ?
About the topic...
It's better to use Trinidad's dataTable than Tomahawk's because:
1) you don't have this problem :)
2) it has support for lazy-loading of the data.
3) it has support for AJAX, if needed.
For more info, see:
http://pmuir.bleepbleep.org.uk/2007/04/backing-trinidads-datatable-with-seam.html
There is also another approach which uses a very straightforward approach, but it requires a lot more work:
http://balusc.blogspot.com/2008/10/effective-datatable-paging-and-sorting.html
Another approach what may work (but Im not sure about it) is something like this:
//request-scoped
public class MyBackingBean {
private List<Data> myData; //session-scoped or cached somewhere else
public List<Data> getData() {
this.myData = ... //load the data and put it in some scope (session or something else)
return this.myData;
}
public void add(Data d) {
this.myData.add(d);
getData(); //refresh the cache
}
//etc. for the other CRUD methods
}
Basically, just refresh the cache each time you add or delete something from the List.
And in your jsf page:
<h:dataTable value="#{myBean.data}">
...
</h:dataTable>
which calls getData() and picks the data from the cache.
From my own experience and the things I've read on the internet, Tomahawk is not the best framework to use with JSF. You might consider to use Trinidad or RichFaces instead, which are more stable.
Nowadays, I use Seam which already includes JSF 1.2 (and soon also JSF2.1), Facelets and RichFaces and this combination works great.
But Seam only works with >=Java 1.5.
Cheers,
Serkan