3

I'm trying to create a page where you click a button and it populates a richfaces datatable with a dynamic number of columns (eventually this will be a lookup, but for now i'm just trying to get a button to populate hardcoded data);

The problem is that the first time i click the button, the page refreshes as expected and the datatable appears, but with no columns or data. If i click the button again, everything appears as normal.

Can anyone tell me what i'm doing wrong that i need to click the button twice?

    <a4j:form id="searchForm" style="height: 100%;" ajaxSubmit="false">
    ...
        <h:commandButton value="Search" action="#{tableBacking.search}" />
    ...
        <rich:scrollableDataTable id="resultsTable" value="#{tableBacking.results}" var="results" 
              rows="500" >
           <rich:column>
                <f:facet name="header">
                    <h:outputText value="Row" />
                </f:facet>

                <h:outputText value="#{row}" />
            </rich:column>

            <rich:columns value="#{tableResultsBacking.columns == null ? '' : tableResultsBacking.columns}" var="columns" index="ind" id="column#{ind}" sortBy="#{columns.header}" >
                <f:facet name="header">
                    <h:outputText value="#{columns.header}" />
                </f:facet>

                <h:outputText value="#{results[ind].data}" />
            </rich:columns>

         </rich:scrollableDataTable>
    </a4j:form>

backing bean

public class TableLookupBacking {

    private List<SelectItem> allTables = null;
    private List<List<Column>> results = null;

    public TableLookupBacking() throws Exception {}

    public List<SelectItem> getAllTables() {

        if(allTables == null) {
            allTables = new ArrayList<SelectItem>();
            DataDao dd = new DataDao();
            try {
                allTables = dd.getTableNames();
            } catch (Exception e) {
                // TODO Add error message here
                e.printStackTrace();
            }
        }

        return allTables;
    }

    public void search() {

        DataDao dd = new DataDao();
        try {
            results = dd.getData();
        } catch (Exception e) {
            // TODO Add error message here
            e.printStackTrace();
        }
        columns = new ArrayList<Column>();

        for (List<Column> row : results) {
            for (Column c : row) {
                if(columns.size() < row.size()) {
                    columns.add(new Column(c.getHeader()));
                }
            }
        }

        FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("columns", columns);
    }
// getters and setters
}

Here's a request scoped bean so that the columns get generated in the constructor.

public class TableResultsBacking {

    private List<TableData> columns = null;

    public TableResultsBacking() throws IOException {
        if(null != FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("columns")) {
            columns = (List<TableData>) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("columns");
        } 
    }

    public List<TableData> getColumns() throws Exception {
        return columns;
    }
    public void setColumns(ArrayList<TableData> columns) {
        this.columns = columns;
    }
}
Catfish
  • 18,876
  • 54
  • 209
  • 353

2 Answers2

2

It seems that the page doesn't actually load correctly after the very first 2 clicks. It takes 2 clicks for every single search. Apparently after the very first 2 clicks, the data will show up correctly for the next clicks, but it will only display the previous searched number of columns.

I ended up adding a method that when a value is selected in the dropdown, i query the database and get the number of columns and set columns then. That way when the page is refreshed, the columns already exist.

Catfish
  • 18,876
  • 54
  • 209
  • 353
1

You told that TableResultsBacking is request scoped bean, but you putted it in session, which means it is session scoped. That's the reason why you don't see anything for the first time. In second request you view columns of first request, because columns stayed in the session. Try adding attribute immediate="true" to command button.

Chandra Sekhar
  • 16,256
  • 10
  • 67
  • 90
partlov
  • 13,789
  • 6
  • 63
  • 82
  • I'm not sure what you mean. TableResultsBacking is request scoped and TableLookupBacking is session scoped. – Catfish Dec 27 '12 at 19:13
  • Adding `immediate="true"` doesn't do anything different. – Catfish Dec 27 '12 at 19:19
  • Sorry, my attention was on "columns" session attribute. You have to backing beans here. How you can be shore that TableResultsBacking will be created later? If it is created first than the columns session attribute will be null. Try to put breakpoint to `search` method and `TableResultsBacking` constructor and see which is first reached. – partlov Dec 27 '12 at 19:24
  • TableResultsBacking is reached first. The thing i still don't understand is that after you click twice to get results showing, you can then choose another value from the dropdown and click search only 1 time and the correct columns appear. – Catfish Dec 27 '12 at 19:30
  • OK, you first click button, TableResultBacking bean is created but columns is null. Than search method is called, and columns is added to session. Next click is the same, but now you have columns from previous request and shows it. Try move columns to session scoped bean and refer your columns value to it, just for testing. – partlov Dec 27 '12 at 19:35
  • I moved everything back to one bean (TableLookupBacking) which is session scoped and i have the same issue. Also, i don't think i'm getting results from the previous request because after i click search twice and get the expected columns, if i search for a different value, i click search only 1 more time and i get the expected columns. The problem is the first search of every session is when i have to click twice. – Catfish Dec 27 '12 at 19:39