1
votes

I have a simple requirement: The number of columns of my <tr:table/> is dynamic. I will have a list of objects, someBean.features which will determine how many columns are rendered.

The following diagram should clarify my requirement.

Table with dynamic columns

In the code that I was given, there was usage of the JSTL <c:forEach/> tag which obviously created problems when used in a JSF environment. They had done something like this:

<tr:table value="#{someBean.values}">
    <tr:column headerText="Name">
        <tr:outputText value="#{someBean.name}"/>
    </tr:column>
    <c:forEach var="col" items="#{someBean.features}">
        <tr:column headerText="Column-#{col.id}">
            <tr:outputText value="#{col.name}"/>
        </tr:column>
    </c:forEach>
</tr:table>

But when I profiled the above code, the method someBean.getValues which is the input to the <tr:table/> tag above was getting called several thousands of times rather than about 20. This - as I figured out - was due to the fact that <c:forEach/> tag is a compile time tag where as <tr:*/> are render time tags.

So, here's what I intend to do (replace <c:forEach/> with <tr:iterator/>:

<tr:table value="#{someBean.values}">
    <tr:column headerText="Name">
        <tr:outputText value="#{someBean.name}"/>
    </tr:column>
    <tr:iterator var="col" value="#{someBean.features}">
        <tr:column headerText="Column-#{col.id}">
            <tr:outputText value="#{col.name}"/>
        </tr:column>
    </tr:iterator>
</tr:table>

But, for some reason, the <tr:iterator/> doesn't seem to like being placed inside a <tr:table/> and it never gets executed.

Any solution, tips, guidelines will be greatly appreciated.

Oh and we're using JSF 1.1 with a MyFaces Trinidad 1.0.13 implementation.

Thanks.

2

2 Answers

1
votes

A getter call is a particularly cheap operation. If your getters do their job as they are intented for, just returning the bean property, then this should really not harm.

This concern gives me the impression that you're incorrectly doing some expensive business job inside a getter method instead of a constructor or some event method which is invoked only once upon a request. You should really fix that accordingly. Getters should not do any business job or at highest just do some lazy loading.

As to why the <c:forEach> works and the <tr:iterator> not, that's because JSTL tags runs during view build time, not during view render time and that the only valid child of an UIData component is an UIColumn component. Basically, when the view is to be built, all JSTL tags will run and you end up with a pure JSF view with all <tr:column> in the right places already. When the view is to be rendered, all JSF tags will run and you end up with a pure HTML result which can then be sent to the browser.

See also:

1
votes

Only way i think (about which you may know already ;) ) is to write extend UIXTable and provide a custom taghandler to process <tr:columns items="#{columns}"> and expand the columns array into html columns