DataTable with dynamic columns

20,699

JSTL and JSF doesn't run in sync as you'd expect from the coding. It's more so that JSTL first processes the entire page from top to bottom first and then hands over the result to JSF for further processing. The #{row} is unavailable at the time JSTL is busy, so your attempt indeed won't work.

The linked topic indeed mentions deprecated methods, but the topic is also aged and discusses legacy JSF 1.0/1.1. If you explore the current Javadocs of the mentioned methods, you'll see that -as usual- the replacement methods are mentioned. For example, Application#createValueBinding() mentions the following:

Deprecated. This has been replaced by calling getExpressionFactory() then ExpressionFactory.createValueExpression(javax.el.ELContext, java.lang.String, java.lang.Class).

You can find some concrete examples of dynamically populating a datatable this way in this article.

As to 3rd party component libraries, RichFaces has a rich:columns component which is designed for exactly this purpose.

Share:
20,699
DaveyDaveDave
Author by

DaveyDaveDave

14 years of Java development experience in a broad range of industries and companies of all shapes and sizes.

Updated on September 01, 2020

Comments

  • DaveyDaveDave
    DaveyDaveDave over 3 years

    I am completely new to JSF, and just attempting a proof of concept to decide whether it will be useful for a project. My POC simply consists of a single page, with a table, containing some data.

    The number of columns (as well as the number of rows) is dynamic, loaded from a database before the page is rendered.

    With the following, I get two static columns with the appropriate number of rows, as I'd expect:

    <h:dataTable id="data" value="#{viewDataBean.dataRows}" var="row">
        <h:column>
            <f:facet name="header">
                <h:outputText value="Col 1"/>
            </f:facet>
            <h:outputText value="#{row.values[0].value}"/>
        </h:column>
        <h:column>
            <f:facet name="header">
                <h:outputText value="Col 2"/>
            </f:facet>
            <h:outputText value="#{row.values[1].value}"/>
        </h:column>
    </h:dataTable>
    

    What I wanted to do was to add a <c:forEach...> around a single set of <h:column>...</h:column> tags, to iterate over the number of columns, but that didn't work - I tried a variety of combinations, but I was expecting something like this to work:

    <h:dataTable id="data" value="#{viewDataBean.dataRows}" var="row">
        <c:forEach items="#{row.values}" var="val">
            <h:column>
                <f:facet name="header">
                    <h:outputText value="Col 1"/>
                </f:facet>
                <h:outputText value="#{val.value}"/>
            </h:column>
        </c:forEach>
    </h:dataTable>
    

    From Googling, I've read various vague comments like 'that's not the way to do it', but I haven't been able to find any particularly compelling examples of the right way. Someone mentioned building the DataTable in the backing bean, but the only example of that I could find was http://forums.sun.com/thread.jspa?threadID=577589. It worked, but felt kind of clumsy, especially since some of the methods used are deprecated.

    At the moment, it's looking unlikely that I'll be able to use any libraries other than core JSF, but that might change if absolutely necessary. Can anyone shed any light on the right way to do this? It seems like it should be pretty simple, so I'm sure I'm just missing something obvious.