3
votes

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;
    }
}
2
I guess this should work if your managed bean has Session scope or wider. Otherwise, you could make it work using the RichFaces @KeepAlive annotation in your managed bean in order to prolong the managed bean life. - Luiggi Mendoza
The bean is session scoped. - Catfish
@Catfish if you provide your screen shots after every events, it helps more to understand - Jubin Patel
Screenshots have been added and question has been updated with my latest code - Catfish

2 Answers

2
votes

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.

1
votes

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.