ICEfaces
  1. ICEfaces
  2. ICE-8378

Add an ace:columns component that will work with the ace:dataTable

    Details

    • Type: New Feature New Feature
    • Status: Closed
    • Priority: Major Major
    • Resolution: Won't Fix
    • Affects Version/s: EE-3.0.0.GA
    • Fix Version/s: None
    • Component/s: ACE-Components
    • Labels:
      None
    • Environment:
      All

      Description

      Component Request: Currently there is no equivalent component to the ice:columns component that will work with the ace:dataTable. This request is to create a new ace:columns component that will work in the same way the ice:columns component worked. This would take in a DataModel and create the necessary columns for the model.

        Issue Links

          Activity

          Hide
          Arran Mccullough added a comment -

          The following is a sample of how this could be accomplished with the current code:

          <ace:dataTable value="..." var="row">
          <ui:repeat value="#

          {bean.columns}

          " var="colModel">
          <ace:column sortBy="#

          {row[colModel.propertyName]}" headerText="# {row[colModel.headerText]}">
          <h:outputText value="#{row[colModel.propertyName]}

          " />
          </ace:column>
          </ui:repeat>
          </ace:dataTable>

          Of course different backing bean code would need to be used other than the DataModel

          Show
          Arran Mccullough added a comment - The following is a sample of how this could be accomplished with the current code: <ace:dataTable value="..." var="row"> <ui:repeat value="# {bean.columns} " var="colModel"> <ace:column sortBy="# {row[colModel.propertyName]}" headerText="# {row[colModel.headerText]}"> <h:outputText value="#{row[colModel.propertyName]} " /> </ace:column> </ui:repeat> </ace:dataTable> Of course different backing bean code would need to be used other than the DataModel
          Hide
          Arran Mccullough added a comment -

          Here is a tutorial showing how to do this with the existing components: http://wiki.icesoft.org/display/ICE/DataTable+Dynamic+Columns

          Show
          Arran Mccullough added a comment - Here is a tutorial showing how to do this with the existing components: http://wiki.icesoft.org/display/ICE/DataTable+Dynamic+Columns
          Hide
          Ladislav Gatial added a comment -

          Are you sure the example works ? I tried it as a prototype with added lazy model columns sorting and filtering enabled, and it does not work, when you try to sort or filter by any column, you get an error cause the property expression is not properly resolved.
          the SortCriteria and the filters contain a bad resolved field name 'property]'
          I think there is a bug in ace:DataTable in ComponentUtils.resolveField(expression);
          this method is used when resolving the sortBy and filterBy expressions, but it only parses the string, it does not really resolve the valueExpression in case of dynamic columns.

          See the sources of my prototype, in the attachment.

          java.lang.RuntimeException: java.lang.NoSuchMethodException: sk.softworks.prototypes.bookshop.web.Car.getProperty]()
          	at sk.softworks.prototypes.bookshop.web.LazySorter.compare(LazySorter.java:28)
          	at java.util.Arrays.mergeSort(Arrays.java:1270)
          	at java.util.Arrays.mergeSort(Arrays.java:1281)
          	at java.util.Arrays.mergeSort(Arrays.java:1281)
          	at java.util.Arrays.mergeSort(Arrays.java:1281)
          	at java.util.Arrays.sort(Arrays.java:1210)
          	at java.util.Collections.sort(Collections.java:157)
          	at sk.softworks.prototypes.bookshop.web.LazyCarDataModel.sort(LazyCarDataModel.java:79)
          	at sk.softworks.prototypes.bookshop.web.LazyCarDataModel.load(LazyCarDataModel.java:51)
          	at org.icefaces.ace.component.datatable.DataTable.loadLazyData(DataTable.java:1310)
          	at org.icefaces.ace.component.datatable.DataTableRenderer.encodeTableBody(DataTableRenderer.java:209)
          	at org.icefaces.ace.component.datatable.DataTableRenderer.encodeTable(DataTableRenderer.java:181)
          	at org.icefaces.ace.component.datatable.DataTableRenderer.encodeEntirety(DataTableRenderer.java:142)
          	at org.icefaces.ace.component.datatable.DataTableRenderer.encodeEnd(DataTableRenderer.java:107)
          	at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:875)
          	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1764)
          	at javax.faces.render.Renderer.encodeChildren(Renderer.java:168)
          	at org.icefaces.impl.renderkit.RendererWrapper.encodeChildren(RendererWrapper.java:49)
          	at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
          	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1757)
          	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1760)
          	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1760)
          	at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:402)
          	at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
          	at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:288)
          	at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
          	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
          	at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
          	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)
          	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
          	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
          	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
          	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
          	at org.apache.tomee.catalina.OpenEJBValve.invoke(OpenEJBValve.java:45)
          	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
          	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
          	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
          	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
          	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
          	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
          	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
          	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
          	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
          	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
          	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
          	at java.lang.Thread.run(Thread.java:680)
          Caused by: java.lang.NoSuchMethodException: sk.softworks.prototypes.bookshop.web.Car.getProperty]()
          	at java.lang.Class.getMethod(Class.java:1605)
          	at sk.softworks.prototypes.bookshop.web.LazySorter.compare(LazySorter.java:21)
          	... 45 more
          
          Show
          Ladislav Gatial added a comment - Are you sure the example works ? I tried it as a prototype with added lazy model columns sorting and filtering enabled, and it does not work, when you try to sort or filter by any column, you get an error cause the property expression is not properly resolved. the SortCriteria and the filters contain a bad resolved field name 'property]' I think there is a bug in ace:DataTable in ComponentUtils.resolveField(expression); this method is used when resolving the sortBy and filterBy expressions, but it only parses the string, it does not really resolve the valueExpression in case of dynamic columns. See the sources of my prototype, in the attachment. java.lang.RuntimeException: java.lang.NoSuchMethodException: sk.softworks.prototypes.bookshop.web.Car.getProperty]() at sk.softworks.prototypes.bookshop.web.LazySorter.compare(LazySorter.java:28) at java.util.Arrays.mergeSort(Arrays.java:1270) at java.util.Arrays.mergeSort(Arrays.java:1281) at java.util.Arrays.mergeSort(Arrays.java:1281) at java.util.Arrays.mergeSort(Arrays.java:1281) at java.util.Arrays.sort(Arrays.java:1210) at java.util.Collections.sort(Collections.java:157) at sk.softworks.prototypes.bookshop.web.LazyCarDataModel.sort(LazyCarDataModel.java:79) at sk.softworks.prototypes.bookshop.web.LazyCarDataModel.load(LazyCarDataModel.java:51) at org.icefaces.ace.component.datatable.DataTable.loadLazyData(DataTable.java:1310) at org.icefaces.ace.component.datatable.DataTableRenderer.encodeTableBody(DataTableRenderer.java:209) at org.icefaces.ace.component.datatable.DataTableRenderer.encodeTable(DataTableRenderer.java:181) at org.icefaces.ace.component.datatable.DataTableRenderer.encodeEntirety(DataTableRenderer.java:142) at org.icefaces.ace.component.datatable.DataTableRenderer.encodeEnd(DataTableRenderer.java:107) at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:875) at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1764) at javax.faces.render.Renderer.encodeChildren(Renderer.java:168) at org.icefaces.impl.renderkit.RendererWrapper.encodeChildren(RendererWrapper.java:49) at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845) at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1757) at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1760) at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1760) at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:402) at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131) at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:288) at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) at org.apache.tomee.catalina.OpenEJBValve.invoke(OpenEJBValve.java:45) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang. Thread .run( Thread .java:680) Caused by: java.lang.NoSuchMethodException: sk.softworks.prototypes.bookshop.web.Car.getProperty]() at java.lang. Class .getMethod( Class .java:1605) at sk.softworks.prototypes.bookshop.web.LazySorter.compare(LazySorter.java:21) ... 45 more
          Hide
          Russell Lewandowski added a comment -

          While this is not an ace:columns solution. This is a viable workaround with c:forEach with LazyDataModel, filterBy and sortBy.

          In the non-LazyDataModel ace:dataTable, the ComponentUtils#resolveField(expression) tries to strip out the column name from what looks like EL. This does not work for LazyDataModel with c:forEach since it is not resolved as EL. The following is a snippet of the c:forEach loop and is based on the Dynamic Columns tutorial:

          My.xhtml
          <c:forEach items="${alarmManaged.columns}" var="colModel">
            <ace:column headerText="#{colModel.headerText}" styleClass="left" filterMatchMode="contains" sortBy="#{colModel.value}" filterBy="#{colModel.value}">
              #{alarmGroup.getDynamic(colModel.value)}
            </ace:column>
          </c:forEach> 
          

          Note that in the above code, only the field name is passed to the LazyDataModel and not a list of values to sort or filter on for the Non-LazyDataModel's. To make filterBy work, the LazyDataModel needs the resolved EL. So in the DataTable.java class of ICEFaces 3.2 (or 3.3.SNAPSHOT), I have modified the getFilters() method.

          org.icefaces.ace.component.datatable.DataTable.java
          protected Map<String,String> getFilters() {
            HashMap<String, String> map = new HashMap<String, String>();
            for (Column c : getColumns()) {
              String value = c.getFilterValue();
              if (value != null && (value.length() > 0)) {
                if(this.model!=null && this.model instanceof LazyDataModel) {
                  FacesContext context = FacesContext.getCurrentInstance();
                  ELContext elContext = context.getELContext();
                  map.put((String)c.getValueExpression("filterBy").getValue(elContext),value);
                } else {
                  map.put(ComponentUtils.resolveField(c.getValueExpression("filterBy")), value);
                }
              }
            }
            return map;
          }
          

          This takes care of the filterBy stuff. The sortBy stuff does not need to be modified in the ICEfaces source. This can be done in your extended LazyDataModel since the ValueExpression is embedded in the SortCriteria. All we need to do is resolve the ValueExpression.

          MyLazyDataModel.java
          public List<AlarmGroup> load(int first, int pageSize, SortCriteria[] sortCriteria, java.util.Map<java.lang.String,java.lang.String> filters) {
            try {
              if(filters!=null && filters.size()>0) {
                for(String columnName: filters.keySet()) {
                  String filterValue = filters.get(columnName);
                  // Do something with columnName and filterValue
                }
              }
          			
              FacesContext context = FacesContext.getCurrentInstance();
              ELContext elContext = context.getELContext();
              for(SortCriteria s: sortCriteria) {
                String columnName = (String)s.getExpression().getValue(elContext);
                boolean ascending = s.isAscending();
                // Do something with columnName and ascending
              }
          			
              // Query Database with filter and sort information and return List
            } catch(Exception e) {
              // Handle exception
            }
          }			
          

          This is working for me. I have put a request in to get contributor status so I can submit formal changes.

          Show
          Russell Lewandowski added a comment - While this is not an ace:columns solution. This is a viable workaround with c:forEach with LazyDataModel, filterBy and sortBy. In the non-LazyDataModel ace:dataTable, the ComponentUtils#resolveField(expression) tries to strip out the column name from what looks like EL. This does not work for LazyDataModel with c:forEach since it is not resolved as EL. The following is a snippet of the c:forEach loop and is based on the Dynamic Columns tutorial: My.xhtml <c:forEach items= "${alarmManaged.columns}" var = "colModel" > <ace:column headerText= "#{colModel.headerText}" styleClass= "left" filterMatchMode= "contains" sortBy= "#{colModel.value}" filterBy= "#{colModel.value}" > #{alarmGroup.getDynamic(colModel.value)} </ace:column> </c:forEach> Note that in the above code, only the field name is passed to the LazyDataModel and not a list of values to sort or filter on for the Non-LazyDataModel's. To make filterBy work, the LazyDataModel needs the resolved EL. So in the DataTable.java class of ICEFaces 3.2 (or 3.3.SNAPSHOT), I have modified the getFilters() method. org.icefaces.ace.component.datatable.DataTable.java protected Map< String , String > getFilters() { HashMap< String , String > map = new HashMap< String , String >(); for (Column c : getColumns()) { String value = c.getFilterValue(); if (value != null && (value.length() > 0)) { if ( this .model!= null && this .model instanceof LazyDataModel) { FacesContext context = FacesContext.getCurrentInstance(); ELContext elContext = context.getELContext(); map.put(( String )c.getValueExpression( "filterBy" ).getValue(elContext),value); } else { map.put(ComponentUtils.resolveField(c.getValueExpression( "filterBy" )), value); } } } return map; } This takes care of the filterBy stuff. The sortBy stuff does not need to be modified in the ICEfaces source. This can be done in your extended LazyDataModel since the ValueExpression is embedded in the SortCriteria. All we need to do is resolve the ValueExpression. MyLazyDataModel.java public List<AlarmGroup> load( int first, int pageSize, SortCriteria[] sortCriteria, java.util.Map<java.lang. String ,java.lang. String > filters) { try { if (filters!= null && filters.size()>0) { for ( String columnName: filters.keySet()) { String filterValue = filters.get(columnName); // Do something with columnName and filterValue } } FacesContext context = FacesContext.getCurrentInstance(); ELContext elContext = context.getELContext(); for (SortCriteria s: sortCriteria) { String columnName = ( String )s.getExpression().getValue(elContext); boolean ascending = s.isAscending(); // Do something with columnName and ascending } // Query Database with filter and sort information and return List } catch (Exception e) { // Handle exception } } This is working for me. I have put a request in to get contributor status so I can submit formal changes.
          Hide
          Russell Lewandowski added a comment -

          This is a better mod to DataTable.java class. It handles both columns created in a c:forEach loop and not in a loop for LazyDataModel.

          org.icefaces.ace.component.datatable.DataTable.java
          protected Map<String,String> getFilters() {
            HashMap<String, String> map = new HashMap<String, String>();
            for (Column c : getColumns()) {
              String value = c.getFilterValue();
              if (value != null && (value.length() > 0)) {
                if(this.model!=null && this.model instanceof LazyDataModel) {
                  FacesContext context = FacesContext.getCurrentInstance();
                  ELContext elContext = context.getELContext();
                  String columnName = (String)c.getValueExpression("filterBy").getValue(elContext);
                  if(columnName!=null) {
                    map.put(columnName,value);
                  } else {
                    map.put(ComponentUtils.resolveField(c.getValueExpression("filterBy")),value);
                  }
                } else {
                  map.put(ComponentUtils.resolveField(c.getValueExpression("filterBy")), value);
                }
              }
            }
            return map;
          }
          
          Show
          Russell Lewandowski added a comment - This is a better mod to DataTable.java class. It handles both columns created in a c:forEach loop and not in a loop for LazyDataModel. org.icefaces.ace.component.datatable.DataTable.java protected Map< String , String > getFilters() { HashMap< String , String > map = new HashMap< String , String >(); for (Column c : getColumns()) { String value = c.getFilterValue(); if (value != null && (value.length() > 0)) { if ( this .model!= null && this .model instanceof LazyDataModel) { FacesContext context = FacesContext.getCurrentInstance(); ELContext elContext = context.getELContext(); String columnName = ( String )c.getValueExpression( "filterBy" ).getValue(elContext); if (columnName!= null ) { map.put(columnName,value); } else { map.put(ComponentUtils.resolveField(c.getValueExpression( "filterBy" )),value); } } else { map.put(ComponentUtils.resolveField(c.getValueExpression( "filterBy" )), value); } } } return map; }
          Hide
          Nils Lundquist added a comment -

          Thanks Russell, however Ladislav posted this issue throughout our issue tracker and forums, and I responded to him on our forums, as is expected for front-line end user support. Until a support request is codified as a bug and a test case isolated, we prefer to keep speculation and discussion in the forum.

          Your solution mirrors the resolutions I'd proposed on the forums. Something similar is planned for implementation in a coming overhaul of lazy loading functionality, so that a dynamic column implementation passes identifying information as part Lazy Loading filter/sort criteria.

          Show
          Nils Lundquist added a comment - Thanks Russell, however Ladislav posted this issue throughout our issue tracker and forums, and I responded to him on our forums, as is expected for front-line end user support. Until a support request is codified as a bug and a test case isolated, we prefer to keep speculation and discussion in the forum. Your solution mirrors the resolutions I'd proposed on the forums. Something similar is planned for implementation in a coming overhaul of lazy loading functionality, so that a dynamic column implementation passes identifying information as part Lazy Loading filter/sort criteria.
          Hide
          Nils Lundquist added a comment -

          The use of ui:repeat or c:forEach to dynamically create your set of columns is the supported way to create dynamic columns for the ace:dataTable.

          Show
          Nils Lundquist added a comment - The use of ui:repeat or c:forEach to dynamically create your set of columns is the supported way to create dynamic columns for the ace:dataTable.
          Hide
          Ken Fyten added a comment -

          Added dependency on new live scroll support with Lazy mode JIRA.

          Show
          Ken Fyten added a comment - Added dependency on new live scroll support with Lazy mode JIRA.

            People

            • Assignee:
              Unassigned
              Reporter:
              Arran Mccullough
            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: