سؤال

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> 
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top