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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With