JSF Composite component <f:ajax> contains an unknown id - cannot locate it in the context of the component
Asked Answered
M

2

8

I'm trying to update a parent component from a composite component event using f:ajax.

The composite component is here:

<cc:interface>
    <cc:attribute name="update" />
    <cc:attribute name="customid" required="true"/>
    <cc:attribute name="val" required="true"/>
    <cc:attribute name="selectedvalue" required="true"/>
</cc:interface>
<cc:implementation>
    <h:panelGrid columns="2" style="font-size: 10px" >
        <p:selectOneMenu id="#{cc.attrs.customid} value="#{cc.attrs.selectedvalue}">
            <f:selectItems value="#{cc.attrs.val}"/>
            <f:ajax event="change" render="#{cc.attrs.update" />
        </p:selectOneMenu>
        <p:commandButton type="button" icon="ui-icon-plus" onclick="dlg.show();" />
    </h:panelGrid>
</cc:implementation>

Now when using this component as follows:

<h:form>
    <ez:combo customid="make" val="#{vehicleBean.makes}" selectedvalue="#vehicleBean.vehicle.make}" update="model"  />
    <p:selectOneMenu id="model" value="#{vehicleBean.vehicle.model}">
        <f:selectItems value="#{vehicleBean.models}" />
    </p:selectOneMenu>
</h:form>

I get the following error:

contains an unknown id 'model' - cannot locate it in the context of the component make

Manilla answered 25/3, 2012 at 8:1 Comment(1)
isn't <f:ajax event="change" render="#{cc.attrs.update" /> wrong (missing } )Madai
W
15

Since the component to update is outside the cc you have to address it in a different way. First give your form an id:

<h:form id="myform">

Then address the target component from your cc like this:

render=":myform:model"

Notice the trailing colon which lets JSF search the attribute from the document root.

Whacking answered 25/3, 2012 at 8:31 Comment(2)
Still unable to find.. <f:ajax> contains an unknown id ':myform:model'Manilla
Check the generated html source in browser for the correct id. Maybe you have another NamingContainer in your document tree which you didn't show in your questionWhacking
S
4

I had the same problem a while ago, just for information, I checked the jsf mojara implementation's sources; here is how it seems to work: The class ajaxBehaviorRendered, when encounters a f:ajax element to render, analyses the content of the render attribute through its method getResolvedId:


private static String getResolvedId(UIComponent component, String id) {

        UIComponent resolvedComponent = component.findComponent(id);
        if (resolvedComponent == null) {
...

The point is the method findComponent: this one needs of base component base as a strat point for searching in the component tree. If the identifier begins with the char ":", the component base is the viewRoot.



    UIComponent base = this;
     if (expr.charAt(0) == sepChar) {
        // Absolute searches start at the root of the tree
        while (base.getParent() != null) {
            base = base.getParent();
         }
        expr = expr.substring(1);
    }

Else the base component is the current component's closest parent of type NamingContainer (that is, your composite component where you are defining your ajax component).



    //Treat remainder of the expression as relative
    else if (!(base instanceof NamingContainer)) {
        // Relative expressions start at the closest NamingContainer or root
        while (base.getParent() != null) {
            if (base instanceof NamingContainer) {
                break;
            }
            base = base.getParent();
        }
    }

Then, in both cases, it starts to search the component with the given identifier from this start.

This behaviour is the one specified from jsf.

From my point of you, if you need to reference a component outside the composite, you have to define the complete name, usind the prefix ':' followed by the 'cc.clientId' attribute.

Standpipe answered 4/2, 2013 at 14:43 Comment(4)
Very intersting point, thank you. BTW, why can't we just specify the render attribute as :client_id ommiting the parent form id?Actress
I haven't work with JSF since 2 years now, I hope I won't answer something silly. From what I remember (but I am not really sure), the JSF lifecycle, when it process the component tree and find a component inside an form, automatically prefix this component's identifier with the form's identifier. Hence, it cannot resolve the ":client_id" as it real identifier is "form_id:client_id". But it should be reviewed as I lost the focus on JSF during the 2 past years.Standpipe
So, yes, the componentSEarch arlgorithm need the full path to a component. Don't you know if it's a specifiec thing for the Mojarra implementation?Actress
It's a good question. The mojarra implementation is the one from sun (originally the JSF-RI). It would require to review the JSR concerning JSF and check if this behaviour is well-defined or is left to the implementation. It would also be interesting to have the knowledge from someone working with another implementation (like the MyFaces from Apache)Standpipe

© 2022 - 2024 — McMap. All rights reserved.