11 Replies Latest reply on Dec 1, 2008 12:12 PM by christian.yttesen

    rich:dataTable column sorting

    christian.yttesen

      Hi,

      I have some difficulties getting column sorting to work properly.

      Environment:
      1. Resin 3.1.8
      2. JSF 2 (SUN)
      3. Rich faces 3.2.2

      The scenario is that I use a session scoped managed bean. Accessing the page containing the datatable the column sorting works perfect each time I click on a sortable header.

      However accessing the same page later on (same data) only the column sort icon changes state, the table data remains the same (sorting seams not applied). Clicking CTRL + F5 will sort the data, however I still face the same result when clicking the sortable columns.

      The result is the same in IE 7 and FF 3.

      Any ideas?

      NB: If I change the scope of the managed bean to 'request' it works every time - however this is not an option for me. Further I use a binding on the table to a property in my managed bean.

      Thanks,
      Christian

        • 1. Re: rich:dataTable column sorting
          christian.yttesen

          I discovered that the ID of my dataTable changes:

          The first time I access the page (when it works) it is:
          - id="frm2:tblServiceProviders"

          The next time I access the page (not working) it is:
          - id="frm2:tblServiceProviders:-1"

          I explicitly set the ID of my components.

          Does anybody have an idea why the ID is manipulated?

          NB: I have two <h:form /> tags on my page (because I use facelets).

          Regards,
          Christian

          • 2. Re: rich:dataTable column sorting
            ilya_shaikovsky

            1) paste your pages code

            2) "2. JSF 2 (SUN)" you mean 1.2 I think?

            • 3. Re: rich:dataTable column sorting
              christian.yttesen

              1) See below
              2) Yes of cause - 1.2

              JSP:

              <html xmlns="http://www.w3.org/1999/xhtml"
               xmlns:ui="http://java.sun.com/jsf/facelets"
               xmlns:f="http://java.sun.com/jsf/core"
               xmlns:h="http://java.sun.com/jsf/html"
               xmlns:jsp="http://java.sun.com/JSP/Page"
               xmlns:c="http://java.sun.com/jstl/core"
               xmlns:a4j="http://richfaces.org/a4j"
               xmlns:rich="http://richfaces.org/rich">
              
               <f:view>
               <ui:composition template="WEB-INF/templates/t_layout.jsp">
               <ui:define name="menu">
               <h:form id="frmMenu">
               <rich:toolBar itemSeparator="grid">
               <rich:toolBarGroup location="right">
               <h:commandLink action="#{logonBean.invalidateUser}">
               <h:outputFormat value="#{msgs['menu.logoff']}">
               <f:param value="#{imsUserBean.fullname}" />
               </h:outputFormat>
               </h:commandLink>
               </rich:toolBarGroup>
               </rich:toolBar>
               </h:form>
               </ui:define>
               <ui:define name="content">
               <h:form id="frmServiceProviders">
               <rich:spacer width="1" height="50" />
               <rich:panel styleClass="block-center" style="width: 50%;">
               <f:facet name="header">#{msgs['service_provider.select']}</f:facet>
               <rich:dataTable id="tblServiceProviders" value="#{serviceProviderBean.serviceProviders}" var="item" binding="#{serviceProviderBean.table}" columnClasses="text-left full,text-right,text-right,text-right">
               <rich:column id="name" sortBy="#{item.name}">
               <f:facet name="header">
               <h:outputText value="#{msgs['service_provider.name']}" />
               </f:facet>
               <h:commandLink action="#{serviceProviderBean.selectActive}">
               <h:outputText value="#{item.name}" />
               </h:commandLink><br />
               <h:outputText value="#{item.description}" />
               </rich:column>
               <rich:column sortBy="#{item.registeredUsers}">
               <f:facet name="header">
               <h:outputText value="#{msgs['service_provider.registered_users']}" />
               </f:facet>
               <h:outputText value="#{item.registeredUsers}" />
               </rich:column>
               <rich:column sortBy="#{item.maxOnlineUsers}">
               <f:facet name="header">
               <h:outputText value="#{msgs['service_provider.max_online_users']}" />
               </f:facet>
               <h:outputText value="#{item.maxOnlineUsers}" />
               </rich:column>
               <rich:column sortBy="#{item.maxRegisteredUsers}">
               <f:facet name="header">
               <h:outputText value="#{msgs['service_provider.max_registered_users']}" />
               </f:facet>
               <h:outputText value="#{item.maxRegisteredUsers}" />
               </rich:column>
               </rich:dataTable>
               </rich:panel>
               </h:form>
               </ui:define>
               </ui:composition>
               </f:view>
              </html>
              


              Managed bean:
              package dsl.gui.bean;
              
              import java.util.ArrayList;
              import java.util.List;
              
              import javax.annotation.PostConstruct;
              
              import org.apache.log4j.Logger;
              import org.richfaces.component.html.HtmlDataTable;
              
              import com.digiquant.ims.corba.bridge.entity.ServiceProviderType;
              import com.digiquant.ims.ejb.serviceprovider.business.ServiceProviderAgent;
              import com.digiquant.ims.ejb.serviceprovider.valueobject.ServiceProvider;
              
              import dsl.gui.utility.ServiceLocator;
              
              public class ServiceProviderBean extends Bean {
               protected static Logger log = Logger.getLogger(ServiceProviderBean.class);
              
               protected List<ServiceProvider> serviceProviders = new ArrayList<ServiceProvider>();
               protected ServiceProvider activeServiceProvider;
              
               protected HtmlDataTable table;
              
               @PostConstruct
               public void init() {
               loadValidServiceProviders();
               }
              
               public HtmlDataTable getTable() {
               return table;
               }
              
               public void setTable(HtmlDataTable table) {
               this.table = table;
               }
              
               public ServiceProvider getActiveServiceProvider() {
               return activeServiceProvider;
               }
              
               public void setActiveServiceProvider(ServiceProvider activeServiceProvider) {
               this.activeServiceProvider = activeServiceProvider;
               }
              
               public List<ServiceProvider> getServiceProviders() {
               return serviceProviders;
               }
              
               public String listServiceProviders() {
               return "list";
               }
              
               public String selectActive() {
               activeServiceProvider = (ServiceProvider) table.getRowData();
               return "select";
               }
              
               protected void loadValidServiceProviders() {
               // ... code removed ...
               }
              }
              



              • 4. Re: rich:dataTable column sorting
                ilya_shaikovsky

                I think you have to move binding property to a request scoped bean and just save the table properties which you need to access to some session scoped bean inside some actions. Session scoped bindings are sources of many problems including "duplicate id" exceptions and etc.

                • 5. Re: rich:dataTable column sorting
                  nbelaevski

                  My guess is that it's happen because of session-scoped binding. Can you please check if that is so?

                  • 6. Re: rich:dataTable column sorting
                    christian.yttesen

                    I will try to remove the component binding on monday (at work) - I just find it extremely easy to find the "selected" row by using this approach.

                    As I'am new to JSF how would I get hold of the selected row without using a binding? I guess I could just send the rowIndex part of a URL parameter but is that really needed? I would appreciate any other suggestions.

                    Why are component bindings considered bad on session scoped beans?

                    • 7. Re: rich:dataTable column sorting
                      christian.yttesen

                      Update: Removing the component binding "solved/removed" the issue with the column sort.

                      However as I need this to be a session scoped managed bean I will remove the column sorting feature to begin with.

                      I would really like if somebody could explain or post some links to why component bindings are considered as bad practice when using session scoped beans. Also ideas to alternative implementation approaches would be highly appreciated.

                      Is this a bug in the Richfaces implementation? I guess it should work even though its bad practice?

                      Thanks for highlighting the issue to me - I look forward reading about why this is an issue in JSF.

                      Christian

                      • 8. Re: rich:dataTable column sorting
                        christian.yttesen

                        Just for other newbies like me - I got around using component binding for my table by using a setPropertyActionListener:

                        <rich:dataTable ... >
                         <h:commandLink>
                         <f:setPropertyActionListener value="#{item.id}" target="#{bean.idToSelect}" />
                         </h:commandLink>
                        </rich:dataTable>
                        


                        Still - I have to digg out the correct row in my managed bean (based on an ID) so I guess its not perfect...

                        Other suggestions are still appreciated.

                        • 9. Re: rich:dataTable column sorting
                          ilya_shaikovsky

                          http://wiki.java.net/bin/view/Projects/FaceletsFAQ#I_m_getting_Duplicate_ID_Errors
                          http://forum.springframework.org/archive/index.php/t-36780.html (last comment)

                          http://groundside.com/blog/DuncanMills.php?p=457&more=1&c=1&tb=1&pb=1
                          espesially:

                          If you need to store a value then that can be bound to a separate managed bean that lives in session scope. There is no problem in having a binding of the component to one bean in the request scope and the value of that component in another. Think model-view-controller here. Your model exists in the session but the view part (the actual components) are request based. There is a clean separation.


                          http://myfaces.apache.org/orchestra/myfaces-orchestra-core/component-bindings.html
                          especialy
                          request-scoped facade
                          Only a few of the methods on the non-request-scoped backing bean will need access to the bound components. Therefore, these methods can be moved into a request-scoped bean. Add the component binding methods to this request-scoped bean too, and inject a reference to the "real" backing bean into it. Alter the view so that EL expressions that need those component bindings to be evaluated point to the request-scoped bean.

                          Another way of thinking about this is that the "real" backing bean for the page is implemented as request-scoped, and any state it needs to retain is pushed into a "helper" object that is of conversation scope. The request-scoped bean has access to the components without problems.


                          So you could create all of your data beans session scoped. But you should have the components bindings in request scope. And the workarounds could be dangerous because If the problems could appear they will appear for sure. ;)

                          • 10. Re: rich:dataTable column sorting
                            ilya_shaikovsky

                            and many other topics could be googled... ;) So there is nothing about RF.. sessions scoped bindings is a bad JSF practice in general.

                            • 11. Re: rich:dataTable column sorting
                              christian.yttesen

                              Thanks a lot the for information and links - a lot of things suddenly made sence.

                              I rearranged my code to use request scoped "backing bean" with component bindings to the table. This backing bean had its model injected and voila everything is now working perfect and is much better structured.