jsfdatatablerendered-attribute

JSF inner datatable not respecting rendered condition of outer table


<h:dataTable cellpadding="0" cellspacing="0"
    styleClass="list_table" id="OuterItems"
    value="#{valueList.values}" var="item" border="0">
    <h:column rendered="#{item.typeA}">
        <h:dataTable cellpadding="0" cellspacing="0"
        styleClass="list_table" id="InnerItems"
        value="#{item.options}" var="option" border="0">
            <h:column >
                <h:outputText value="Option: #{option.displayValue}"/>
            </h:column>
        </h:dataTable>
    </h:column>
    <h:column rendered="#{item.typeB}">
        <h:dataTable cellpadding="0" cellspacing="0"
        styleClass="list_table" id="InnerItems"
        value="#{item.demands}" var="demand" border="0">
            <h:column >
                <h:outputText value="Demand: #{demand.displayValue}"/>
            </h:column>
        </h:dataTable>
    </h:column>
</h:dataTable>

public class Item{
    ...
    public boolean isTypeA(){
        return this instanceof TypeA;
    }

    public boolean isTypeB(){
        return this instanceof TypeB;
    }
    ...

}

public class typeA extends Item(){
    ...
    public List getOptions(){
        ....
    }
    ...
}

public class typeB extends Item(){
    ...
    public List getDemands(){
        ...
    }
    ....
}

I'm having an issue with JSF. I've abstracted the problem out here, and I'm hoping someone can help me understand how what I'm doing fails. I'm looping over a list of Items. These Items are actually instances of the subclasses TypeA and TypeB. For Type A, I want to display the options, for Type B I want to display the demands. When rendering the page for the first time, this works fine. However, when I post back to the page for some action, I get an error:

[3/26/10 12:52:32:781 EST] 0000008c SystemErr     R   javax.faces.FacesException: Error getting property 'options' from bean of type TypeB
    at com.sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.java:89)
    at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java(Compiled Code))
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:91)
    at com.ibm.faces.portlet.FacesPortlet.processAction(FacesPortlet.java:193)

My grasp on the JSF lifecyle is very rough. At this point, i understand there is an error in the ApplyRequestValues Phases which is very early and so the previous state is restored and nothing changes.

What I don't understand is that in order to fufill the condition for rendering "item.typeA" that object has to be an instance of TypeA. But here, it looks like that object passed the condition even though it was an instance of TypeB. It is like it is evaluating the inner dataTable (InnerItems) before evaluating the outer (outerItems). My working assumption is that I just don't understand how/when the rendered attribute is actually evaluated.


Solution

  •  <h:column rendered="#{item.typeA}">
            <h:dataTable cellpadding="0" cellspacing="0"
            styleClass="list_table" id="InnerItems"
            value="#{item.options}" var="option" border="0"
            rendered="#{item.typeA}"> <!--  THIS IS THE CHANGE -->
                <h:column >
                    <h:outputText value="Option: #{option.displayValue}"/>
                </h:column>
            </h:dataTable>
        </h:column>
    

    Somehow adding the rendered condition directly to the datatable didn't occur to me in my many hour iteration of guesses / egg hunt (I was really desperate). I still don't understand why this didn't work in the first place, but it is working.