0

I have Search form. After clicking on Search button data refreshes, but dataTable columns not (columns get refreshed only on second button click). Apparently I am doing something wrong. Dynamic column code is inspired by PrimeFaces Showcase

myForm.xhtml:

<h:form id="MY_FORM">
    #{myBean.initBean()}
    ...
    <h:panelGrid id="main">
        <h:panelGrid id="buttons">
            <p:commandButton id="submitSearch"
                             value="#{msg['button.execute']}"
                             actionListener="#{myBean.submitSearch}"
                             update="resultPanel"/>
        </h:panelGrid>
    </h:panelGrid>

    <h:panelGrid id="resultPanel" border="0">
        <p:dataTable id="resultTable" var="result" value="#{myBean.searchResults}">
            <p:columns value="#{myBean.columns}" var="column" columnIndexVar="colIndex">
                <f:facet name="header">
                    <h:outputText value="#{column.header}" />
                </f:facet>
                <h:outputText value="#{result[column.property]}" />
            </p:columns>
        </p:dataTable>
    </h:panelGrid>
</h:form>

I've called column calculation method createColumns() from myBean.initBean() and myBean.submitSearch() with the same result (I see it works correctly from debugger).

@ManagedBean("myBean")
@Scope(value = "session")
public class MyBean {
    private ArrayList<HashMap<String,Object>> searchResults;
    private List<ColumnModel> columns;
    ...
    public void initBean() {
        ...
        createColumns(selectedDates);
    }

    public void submitSearch() {
        ...
        ArrayList<HashMap<String, Object>> results = prpRepository.getSearchResultByParams(searchParams);
        createColumns(selectedDates);
    }

    private void createColumns(ArrayList<String> selectedDates){
        columns = new ArrayList<ColumnModel>();   
        columns.add(new ColumnModel("Name", "NAME"));
        columns.add(new ColumnModel("Amount", "AMOUNT"));

        for (int i = 0; i < selectedDates.size(); i++) {
            columns.add(new ColumnModel(selectedDates.get(i), "DATE" + i));
        }

        setColumns(columns);
    }

    public List<ColumnModel> getColumns() {
        return columns;
    }

    public void setColumns(List<ColumnModel> columns) {
        this.columns = columns;
    }
}

Additional information: I am using:

  • Oracle's Implementation of the JSF 2.1 Specification
  • JavaServer Pages API 2.2
  • Springframework 3.1.2 (incl. spring-context, spring-web)
  • Glassfish Javax.annotation 3.1.1
Darkwing
  • 314
  • 9
  • 24
  • Do you have any error log? Glancing over the code, perhaps the issue is the type of `searchResults`. In the example, it's working with an object list (car) while you're using a hashmap list. In your datatable, the `var` attribute is a hashmap, isn't it? – Miguel Jul 14 '15 at 12:01
  • Yes, it is a HashMap. I don't have any errors in log, also I am getting correct table data on first Search button click. On second click also Columns are correct (just added createColumns() method to my question). – Darkwing Jul 14 '15 at 12:18
  • 1
    Is this real code? `#{myBean.initBean()}`? This doesn't make sense. Get rid of it and use a `@PostConstruct` annotated method as shown here: http://stackoverflow.com/questions/5765853/when-should-i-load-the-collection-from-database-for-hdatatable/5765937#5765937 And make sure the bean is view scoped. Perhaps it solves all side effects of doing this. – BalusC Jul 20 '15 at 13:10
  • Thanks. I've changed the code as you recommended and result is the same – Darkwing Jul 20 '15 at 13:21
  • What's the bean scope? Update it's code with imports. What's the environment: JSF implementation and version, PrimeFaces version, which application server? – Vsevolod Golovanov Jul 21 '15 at 15:02
  • 2
    To generate better answers sooner, carefully read http://stackoverflow.com/tags/jsf/info For instance, it's nowhere clear from the question when exactly you're calling `createColumns()`. It would make sense if you do that after you have obtained `selectedDates` somehow, most likely in `submitSearch()`. If you're creating columns **before** you've obtained `selectedDates`, then well, there would logically indeed be no columns in first place. – BalusC Jul 21 '15 at 19:31

2 Answers2

1

The problem is that columns is calculted only once time in the org.primefaces.component.datatable.DataTabe

public List<UIColumn> getColumns() {
       // if(columns == null) {     
            columns = new ArrayList<UIColumn>();
            FacesContext context = getFacesContext();
            char separator = UINamingContainer.getSeparatorChar(context);            
            for(UIComponent child : this.getChildren()) {
                if(child instanceof Column) {
                    columns.add((UIColumn) child);
                }
                else if(child instanceof Columns) {
                    Columns uiColumns = (Columns) child;                    
                    String uiColumnsClientId = uiColumns.getClientId(context);
                    uiColumns.updateModel(); /* missed code */
                    for(int i=0; i < uiColumns.getRowCount(); i++) {
                        DynamicColumn dynaColumn = new DynamicColumn(i, uiColumns);
                        dynaColumn.setColumnKey(uiColumnsClientId + separator + i);
                        columns.add(dynaColumn);
                    }
                }
            }
       // }        
        return columns;
    }

You could comment it and overwrite the class file, or find the DataTable object and setColumns to NULL inside the createColumns method

Nassim MOUALEK
  • 4,702
  • 4
  • 25
  • 44
  • Thank you! I've tried second solution you provided: `DataTable dataTable = (DataTable) FacesContext.getCurrentInstance().getViewRoot().findComponent("MY_FORM:resultTable"); dataTable.setColumns(null);` in the createColumns() method. As an example I've enlarged column count from 5 to 7. As I see at debugger first time `getColumns()` are called column count is equals to 5, after that `createColumns()` is called and getColumns() returns 7 columns as it should, but there are still 5 columns on the screen after that. – Darkwing Jul 23 '15 at 07:10
  • try to add uiColumns.updateModel(); where its commented as missed code, if you dont know how to override a default class package, take a look to the end of this thread http://stackoverflow.com/questions/23867296/postinstantiate-buildsessionfactory-slow-memory-huge-database – Nassim MOUALEK Jul 23 '15 at 11:01
-1

Finally I've worked better with debugger and found an answer. Solution was to put createColumns() method call into columns getter getColumns() as it is called automatically before submitSearch(). My problem was in application lifecycle understanding.

Darkwing
  • 314
  • 9
  • 24
  • 1
    Bad solutions. The getColumns will be called many times, so the create will be called many times to – Kukeltje Jul 22 '15 at 09:16
  • yes, read the last commentby BalusC on your question and act accordingly – Kukeltje Jul 22 '15 at 09:18
  • I don't understand can you be more precise, please. I see from debugger that getColumns() is called before initBean() and submitSearch(). It makes no sense to define columns in this two methods. It is nothing to do with obtaining dates as they are obtained correctly – Darkwing Jul 22 '15 at 09:23
  • Create a GOOD example... an MCVE – Kukeltje Jul 22 '15 at 09:28