8 Replies Latest reply on Sep 23, 2008 10:06 AM by rwijeyra

    rich:columns problem

    rwijeyra

      Hi i'm having a problem with rich:columns to create a datatable with dynamic columns

      I have two Lists, one for the columns and one for the values of each row
      phonebookAttributes, is a list containing attributes with a name, type and additional info (i just need the name for the column)
      phonebookEntries, is a list containing entries, each entry has a list of values (the same length as the attributes list)

      so i would expect to be able to use the rich:columns component the following way:

      My Datatable:

      <rich:dataTable id="phonebookEntryTableId" value="#{phonebookEntries}" var="entry">
       <f:facet name="header">
       <h:outputText value="searchResult" />
       </f:facet>
       <!-- Dynamic Columns -->
       <rich:columns value="#{phonebookAttributes}" var="column" index="index">
       <f:facet name="header">
       <h:outputText value="#{column.name}" />
       </f:facet>
       <h:outputText value="#{entry.values[index]}" />
       </rich:columns>
      </rich:dataTable>
      


      Backing Bean:
      @DataModel
      private List<PhonebookAttribute> phonebookAttributes;
      
      @DataModel
      private List<PhonebookEntry> phonebookEntries;
      


      But the datatable is never showing anything, no dynamic column headers or values. only thing displayed is the main header "searchResults" i added to see if the datatable is rendered at all. the properties phonebookAttributes and phonebookEntries though contain data. i can separately list them in the view.

      Any suggestions? Would really appreciate if someone could help.
      Thanks in advance

        • 1. Re: rich:columns problem

          Which RF version do you use?

          • 2. Re: rich:columns problem
            rwijeyra

            i'm using richfaces 3.2.2.GA

            • 3. Re: rich:columns problem

              Only one reason why columns don't appear at all - empty value binding for columns attribute.

              Are you sure that #{phonebookAttributes} was uninitialized before?

              One little example that reproduces your problem:

              Constructor of #{phonebookEntries} model creates #{phonebookAttributes}.
              But in this case #{phonebookEntries} & #{phonebookAttributes} will be created on rendering phase.
              But columns component needs its value early.




              • 4. Re: rich:columns problem
                rwijeyra

                hmmm, well actually in my case #{phonebookAttributes} is already initialized

                1. phonebook selection -> initializes #{phonebookAttributes}
                2. display list of attributes with textfields -> enter filter values
                3. search button -> initializes #{phonebookEntries}

                -> rerender datatable

                • 5. Re: rich:columns problem

                  No ideas...

                  Try to add <rich:column> with fixed value inside to datatable to be sure that dataTable's value attribute is not a cause.

                  Then try to change value attribute of columns component to fixed string:
                  <rich:columns value="1,2,3" ../> to be sure that columns with headers appear in this case.

                  Then please provide us by more info.
                  If you have possibility to send me your project or its part I will look on this to solve the problem.

                  • 6. Re: rich:columns problem
                    rwijeyra

                    first of all thanks, i think we're heading the right way. i added a fixed string list in the columns value and data is displayed. so it seems the problem is that the phonebookAttributes aren't really ready. but i dont understand why.

                    the phonebookAttributes have been initialized in a request before the dataTable is rerendered.

                    here are some more code snippets that might help

                    main page

                    <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
                     xmlns:s="http://jboss.com/products/seam/taglib" xmlns:ui="http://java.sun.com/jsf/facelets"
                     template="#{theme.layoutWE}">
                    
                     <ui:param name="fwcWindowTitle" value="#{messages.window_title}" />
                    
                     <!-- no toolbar -->
                     <ui:define name="fwcToolbar" />
                    
                     <ui:define name="fwcWest">
                     <ui:include src="phonebookSelector.xhtml" />
                     <ui:include src="phonebookFilter.xhtml" />
                     </ui:define>
                    
                     <ui:define name="fwcEast">
                     <ui:include src="phonebookResult.xhtml" />
                     </ui:define>
                    
                    </ui:composition>
                    


                    phonebookFilter (simplified) ... as you can see, phonebookAttributes is already initialized at this point
                    <a4j:repeat var="phonebookAttribute" value="#{phonebookAttributes}">
                     <h:inputText value="#{phonebookAttribute.value}" />
                    </a4j:repeat>
                    
                    <a4j:commandButton value="search" action="#{phonebookDataManager.search}" reRender="phonebookEntryTableId,
                    phonebookEntryTableIdB, phonebookEntryTableIdC" />
                    


                    phonebookResult
                    <rich:dataTable id="phonebookEntryTableId" value="#{phonebookEntries}" var="entry">
                     <f:facet name="header">
                     <h:outputText value="searchResult" />
                     </f:facet>
                     <!-- Dynamic Columns -->
                     <rich:columns value="#{phonebookAttributes}" var="column" index="index">
                     <f:facet name="header">
                     <h:outputText value="#{column.name}" />
                     </f:facet>
                     <h:outputText value="#{entry.values.get[index]}" />
                     </rich:columns>
                    </rich:dataTable>
                    
                    <!-- shows data from the beginning -->
                    <rich:dataTable id="phonebookEntryTableIdB" value="#{phonebookAttributes}" var="column">
                     <f:facet name="header">
                     <h:outputText value="columnsOnly" />
                     </f:facet>
                     <rich:column>
                     <h:outputText value="#{column.name}" />
                     </rich:column>
                    </rich:dataTable>
                    
                    <!-- shows data after search is called -->
                    <rich:dataTable id="phonebookEntryTableIdC" value="#phonebookEntries}" var="entry">
                     <f:facet name="header">
                     <h:outputText value="searchResultOnly" />
                     </f:facet>
                     <rich:column>
                     <h:outputText value="#{entry.values.get(0)}" />
                     </rich:column>
                    </rich:dataTable>
                    


                    the phonebookDataManager bean
                    @DataModel
                    private List<String> phonebookList;
                    private String phonebookSelection;
                    
                    @DataModel
                    private List<PhonebookAttribute> phonebookAttributes;
                    
                    @DataModel
                    private List<PhonebookEntry> phonebookEntries;
                    
                    /*
                     * Methods
                     */
                    
                    @Factory("phonebookList")
                    public void initializePhonebookList() {
                     try {
                     phonebookList = phonebookService.getPhonebooks();
                     // select first phonebook, if any are found and get attributes
                     if (!phonebookList.isEmpty()) {
                     phonebookSelection = phonebookList.get(0);
                     initializePhonebookAttributes();
                     }
                     } catch (ServiceException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                     }
                    }
                    
                    public void initializePhonebookAttributes() {
                     if (phonebookSelection != null) {
                     try {
                     phonebookAttributes = phonebookService.getPhonebookAttributes(phonebookSelection);
                     } catch (ServiceException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                     }
                     }
                    }
                    
                    public void search() {
                     List<String> searchParams = new ArrayList<String>();
                     for(PhonebookAttribute pbattr : phonebookAttributes) {
                     searchParams.add(pbattr.getValue());
                     }
                     try {
                     phonebookEntries = phonebookService.getPhonebookEntries(phonebookSelection, searchParams);
                     } catch (ServiceException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                     }
                    }
                    


                    • 7. Re: rich:columns problem

                      OK, I got the problem. This is the same thing I spoke about: #{phonebookAttributes} is not initialized at the appropriate time, because you wrapped it by DataModel.
                      DataModel wraps the data after class instance was created.
                      Class instance is creating after the first reference from expression string on the page, exactly during response rendering phase.
                      But columns need the value during tag start phase.

                      This limitation should be described in our guide.

                      Solution in your case:
                      1. just remove @DataModel from phonebookAttributes.
                      2. Add getters/setters for it.
                      3. Use as bean property on the page:

                      <rich:columns value="#{youBeanName.phonebookAttributes}" var="column" index="index">
                       <f:facet name="header">
                       <h:outputText value="#{column.name}" />
                       </f:facet>
                       <h:outputText value="#{entry.values.get[index]}" />
                       </rich:columns>


                      • 8. Re: rich:columns problem
                        rwijeyra

                        aaaah! now i get it, of course, makes sense!!!

                        i knew that the values had to be ready in advance, but i didn't quite understand when and how the @DataModel annotation wraps the data.

                        thanks a lot, it finally works. this was really i a blocker for me.