2
votes

Problem: I am passing an EL expression to a composite component, but the EL expression is being evaluated from inside the composite component, rather than before. The intention being that the EL expression evaluates to a string with is sent to the composite component.

I have a composite component, MenuTable:

<cc:interface>
    <cc:attribute name="model" type="nz.co.tradeintel.web.MenuTable"/>
    <cc.attribute name="updateId" /> 
</cc:interface>

<cc:implementation>
    <h:panelGroup id="menuTable">
    <table>
        <ui:repeat id="repeat1" value="#{cc.attrs.model.rows}" var="row">
            <tr>
            <ui:repeat id="repeat2" value="#{row.contents}" var="entry">
                <td>
                    <p:commandLink action="#{cc.attrs.model.setSelected(entry)}" update="#{cc.attrs.updateId}" value="#{entry.toString()}"/>
                </td>
            </ui:repeat>
            </tr>
        </ui:repeat>
    </table>
    </h:panelGroup>
</cc:implementation>

The intention is that I pass an absolute component ID as the attribute updateId like this:

<p:PanelGroup id="updatingPanel">
    <!-- Lots of components.-->
</p:PanelGroup>
<custom:MenuTable updateId="#{component.clientId}:updatingPanel" model="#{menuBackBean.menuTable}" />  

The problem is, the EL expression for the updateId is evaluated from the scope of the <p:commandLink /> within the composite component, and I get the following error:

javax.faces.FacesException: Cannot find component with identifier ":j_idt37:j_idt39:updatingPanel:j_idt61:repeat1:0:repeat2:0:j_idt65:updatingPanel" referenced from "j_idt37:j_idt39:updatingPanel:j_idt61:repeat1:0:repeat2:0:j_idt65".

Note: JSF thinks I am trying to update a component with and ID of updatingPanel which is inside the composite component.

Why is the EL expression not evaluated from the outer scope: <custom:MenuTable/>?

There are a few related answers, but I don't understand them, such as this one.

Using Mojarra 2.1.15

1

1 Answers

7
votes

EL expressions are not evaluated at the moment the component is built, but at the moment the attribute is accessed. In other words, they're runtime and not buildtime. The #{component} refers to the current UI component at the moment the EL expression is evaluated, which is in your particular case the <p:commandLink>. That explains the different outcome.

You need to approach this differently, without using #{component}. One of the ways is

<p:panelGroup binding="#{updatingPanel}">
    ...
</p:panelGroup>
<custom:MenuTable ... updateId=":#{updatingPanel.clientId}" />

If that still doesn't work, then make sure that you don't use <h:form prependId="false">.

See also: