I have a simple composite component with an optional ajax listener implemented with the richfaces a4j:ajax component.
Here is the interface definition :
<!-- INTERFACE -->
<composite:interface name="inplaceInput">
<composite:attribute name="value" required="true" />
<composite:attribute name="render" default="@this" />
<composite:attribute name="ajaxListener" method-signature="void actionListener(javax.faces.event.AjaxBehaviorEvent)" />
</composite:interface>
The following code works fine using two duplicated blocks with opposite rendered condition :
<composite:implementation>
<rich:inplaceInput value="#{cc.attrs.value}" rendered="#{!empty cc.attrs.ajaxListener}">
<a4j:ajax event="change" render="#{cc.attrs.render}" execute="@this" listener="#{cc.attrs.ajaxListener}" />
</rich:inplaceInput>
<rich:inplaceInput value="#{cc.attrs.value}" rendered="#{empty cc.attrs.ajaxListener}">
<a4j:ajax event="change" render="#{cc.attrs.render}" execute="@this" />
</rich:inplaceInput>
</composite:implementation>
But I'd like to avoid the duplication because my component as to be far more complicated...
Using a rendered condition on the a4j:ajax was my first idea :
<rich:inplaceInput value="#{cc.attrs.value}">
<a4j:ajax event="change" render="#{cc.attrs.render}" execute="@this" listener="#{cc.attrs.ajaxListener}" rendered="#{!empty cc.attrs.ajaxListener}" />
<a4j:ajax event="change" render="#{cc.attrs.render}" execute="@this" rendered="#{empty cc.attrs.ajaxListener}" />
</rich:inplaceInput>
But it doesn't work, and the error is quite obscure:
javax.faces.FacesException: Unable to resolve composite component from using page using EL expression '#{cc.attrs.ajaxListener}'
at com.sun.faces.facelets.tag.TagAttributeImpl$AttributeLookupMethodExpression.invoke(TagAttributeImpl.java:444)
at org.ajax4jsf.component.behavior.MethodExpressionAjaxBehaviorListener.processAjaxBehavior(MethodExpressionAjaxBehaviorListener.java:73)
I tried with a c:if handler because the tree doesn't need to have both components:
<rich:inplaceInput value="#{cc.attrs.value}">
<c:if test="#{!empty cc.attrs.ajaxListener}">
<a4j:ajax event="change" render="#{cc.attrs.render}" execute="@this" listener="#{cc.attrs.ajaxListener}" />
</c:if>
<c:if test="#{empty cc.attrs.ajaxListener}">
<a4j:ajax event="change" render="#{cc.attrs.render}" execute="@this" />
</c:if>
</rich:inplaceInput>
And then got another error (using ajaxListener="#{itemList.updateValue}"):
javax.el.PropertyNotFoundException: /pages/itemList.xhtml @71,81 ajaxListener="#{itemList.updateValue}": Property 'updateValue' not found on type com...ItemListManager
If the attribute was an EL returning a value, I could test a default value. I could also add a boolean attribute to tell if the listener is set... Or add a default method on a componentType bean doing nothing... But that's not pretty...
How can I test if a attribute is set without accessing it's value or method binding ?
Thanks in advance for any idea,
Rgds,
FM
You may use cc.getValueExpression()
from UIComponent
class which will check if Value Expression is defined in the using page of your composite component, like this:
<c:if test="#{!empty cc.getValueExpression('ajaxListener')}">
<a4j:ajax event="change" render="#{cc.attrs.render}" execute="@this" listener="#{cc.attrs.ajaxListener}" />
</c:if>
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