-
1. Re: Extending a richfaces component (HtmlDataScroller).
roykachouh Jul 30, 2009 10:25 AM (in response to roykachouh)For all those who care, I came up with a pretty elegant solution to this...
Here are the steps I've taken...
1st - Create a class that extends com.sun.facelets.tag.AbstractTagLibrary.
This class will be used to create our component library. Also create a component handler class...
Here is my class...public class LtpLibrary extends AbstractTagLibrary { public final static String Namespace = "http://mysite.com/core"; public LtpLibrary() { super(Namespace); this.addConverter("genericSubstringConverter",GenericSubstringConverter.CONVERTER_ID,GenericSubstringConverterHandler.class); this.addComponent("ltpDataScroller",LtpDataScroller.COMPONENT_ID,"org.richfaces.DataScrollerRenderer",LtpDataScrollerHandler.class); Method[] methods = LTPFunctions.class.getMethods(); for (int i = 0; i < methods.length; i++) { if (Modifier.isStatic(methods.getModifiers())) { this.addFunction(methods.getName(), methods); } } } } public class LtpDataScrollerHandler extends ComponentHandler { public LtpDataScrollerHandler(ComponentConfig config) { super(config); } @Override protected UIComponent createComponent(FaceletContext ctx) { return ctx.getFacesContext().getApplication().createComponent(LtpDataScroller.COMPONENT_ID); } }
The component that I create is called ltpDataScroller
2nd - Create a class that extends the Richfaces HtmlDataScrollerpublic class LtpDataScroller extends HtmlDatascroller { public static final String COMPONENT_ID = "com.asc.ltp.web.components.LtpDataScroller"; @Override public int getPageCount() { //here is where you will put actual logic to compute the pages needed for //the datascroller return 100; } }
3rd - Add the following context param in web.xml, and don't forget the tld file in META-INF<context-param> <param-name>facelets.LIBRARIES</param-name> <param-value>/META-INF/ltp-taglib.xml</param-value> </context-param>
Tld file..<facelet-taglib> <library-class>com.asc.ltp.tags.library.LtpLibrary</library-class> </facelet-taglib>
Create a custom scroller listener to listen to the scrolling events...the listener will be responsible for refreshing data in the actual datascroller..public void processScroller(DataScrollerEvent event) { LOG.debug(event); }
Finally, use the newly created component...<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ltp="http://mysite.com/core" xmlns:a4j="https://ajax4jsf.dev.java.net/ajax" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:rich="http://richfaces.org/rich" xmlns:c="http://java.sun.com/jsp/jstl/core"> <ltp:ltpDataScroller scrollerListener="#{ParkApi.commentScrollerListener}" for="commentGrid"/> </ui:composition>
Hope this helps!
-Roy -
2. Re: Extending a richfaces component (HtmlDataScroller).
roykachouh Jul 31, 2009 8:50 AM (in response to roykachouh)I am actually now having issues with this approach...I guess I jumped the gun with this soultion...
the issue i am now having is this...
I am trying to extend the datascroller richfaces component. I want to add some of my own behavior to this component. So what I did was I added a component in my application library by extending the abstracttaglibrary as so...public class LtpLibrary extends AbstractTagLibrary { public final static String Namespace = "http://mysite.com/core"; public LtpLibrary() { super(Namespace); this.addComponent("ltpDataScroller",LtpDataScroller.COMPONENT_ID,"org.richfaces.DataScrollerRenderer",LtpDataScrollerHandler.class); } }
Inside my custom LTP datascroller, I have a custom pagination handler attribute that gets set. The attribute gets set fine on the initial request, however when I try to page thru the dataset by clicking on page 2, the attribute does not get set, and a null pointer exception is thrown as a result. I will add as much code as possible to make clear the issue.
My AjaxComponentHandler...public class LtpDataScrollerHandler extends AjaxComponentHandler { private final TagAttribute scrollerListener; private final TagAttribute paginator; public LtpDataScrollerHandler(ComponentConfig config) { super(config); this.scrollerListener = this.getAttribute("scrollerListener"); this.paginator = this.getAttribute("paginator"); } @Override protected UIComponent createComponent(FaceletContext ctx) { return ctx.getFacesContext().getApplication().createComponent(LtpDataScroller.COMPONENT_ID); } @Override protected void setAttributes(FaceletContext ctx, Object obj) { LtpDataScroller scroller = (LtpDataScroller)obj; ExpressionFactory expressionFactory = ctx.getExpressionFactory(); if(this.scrollerListener!=null){ MethodExpression expression = expressionFactory.createMethodExpression(ctx, scrollerListener.getValue(), null, new Class[] {DataScrollerEvent.class}); scroller.setScrollerListener(expression); } if(this.paginator!=null){ ValueExpression ve = expressionFactory.createValueExpression(ctx, paginator.getValue(), Paginator.class); Paginator paginator = (Paginator) ve.getValue(ctx); scroller.setPaginator(paginator); } } @Override protected MetaRuleset createMetaRuleset(Class type) { return super.createMetaRuleset(type); } }
The class that extends the HTMLDataScroller...public class LtpDataScroller extends HtmlDatascroller{ public static final String COMPONENT_ID = "com.asc.ltp.web.components.LtpDataScroller"; private Paginator paginator; @Override public int getPageCount() { int pageCount = 0; PaginationConfig config = new DefaultPaginationConfig(5,3); pageCount = paginator.determinePageCount(config); return pageCount; } public Paginator getPaginator() { return paginator; } public void setPaginator(Paginator paginator) { this.paginator = paginator; } /*@Override public boolean isRendered() { return paginator.shouldRender(); }*/ }
Is there something I am missing? Why does my paginator attribute get set on the inital rendering, but does not for subsequent ajax requests?
Your help is really appreciated on this one... -
3. Re: Extending a richfaces component (HtmlDataScroller).
nbelaevski Jul 31, 2009 11:40 AM (in response to roykachouh)Hi,
Take a look at documentation about StateHolder interface; especially saveState/restoreState methods. -
4. Re: Extending a richfaces component (HtmlDataScroller).
roykachouh Jul 31, 2009 2:08 PM (in response to roykachouh)Thats great! Worked like a charm, but now I am stuck on another issue...
My Pagination interface is working as expected, when a user clicks on a page in the datascroller, my custom datascroller component, which is only an extention of your datascroller, will delagate operations to a pagination interface. Some examples include a method that retrieves that page count, and another that set the active data list for the datagrid/datatable....
the interface looks like the following:public int determinePageCount(PaginationConfig config); public List<BaseDomain> getActiveDataList();
When the page is first loaded, my application will get data for page 1. Which I configured to only return rows 1 - 5. When the user clicks on page 2, the application again retrieved rows 6 - 10, and set the activeDateList to contain that data. However, richfaces datagrid is not displaying the second page worth of data...
Here is some more code...
My datagrid...<rich:dataGrid id="commentGrid" value="#{ParkApi.parkCommentPaginator.activeDataList}" var="parkComment" columns="1" elements="5">
My custom scroller...<ltp:ltpDataScroller scrollerListener="#{ParkApi.commentScrollerListener.processScroller}" for="commentGrid" paginator="#{ParkApi.parkCommentPaginator}" rendered="#{fn:length(ParkApi.createdPark.commentList) gt 0}"/>
My Datascroller listener class...public class GenericScrollerListener implements DataScrollerListener { protected static Logger LOG = Logger.getLogger(GenericScrollerListener.class); private Paginator paginator; public GenericScrollerListener(Paginator paginator){ this.paginator = paginator; } public void processScroller(DataScrollerEvent event) { LOG.debug("Processing scroll event, retrieving page data for "+event.getPage()); List data = paginator.getDataListForPage(event.getPage(), PaginationConfig.DEFAULT_CONFIG); paginator.setActiveDataList(data); ((LtpDataScroller)event.getSource()).setPage(event.getPage()); } public Paginator getPaginator() { return paginator; } public void setPaginator(Paginator paginator) { this.paginator = paginator; } }
Why won't the datagrid refresh with the newly fetched data...is there a need for the equivalent of a reRender attribute??