Abu Zoha
Abu Zoha

Reputation: 53

JSF Composite component : Error occured when an attribute i.e. valueChangeListener is not available

I have a composite (X) like this:

<composite:interface>
  <composite:attribute name="textValue" />
  <composite:attribute name="textValueChangeListner"
                       method-signature="void valueChanged(javax.faces.event.ValueChangeEvent)" />

<composite:implementation>          
      <ice:inputText
                      value="#{cc.attrs.textValue}"
                      valueChangeListener="#{cc.attrs.textValueChangeListner}"/>

In the JSF page I have something like:

<X:iText
textValue="#{cardBean.getCardValue}"
textValueChangeListner="#{cardHandler.cardValueChanged}" />  

The above code works fine. But it does not work when NO "textValueChangeListner" is passed to the composite from JFace page; i.e:

<X:iText
textValue="#{cardBean.getCardValue}" /> 

Error I got: [javax.enterprise.resource.webcontainer.jsf.lifecycle] Unable to resolve composite component from using page using EL expression '#{cc.attrs.textValueChangeListner}': javax.faces.FacesException: Unable to resolve composite component from using page using EL expression '#{cc.attrs.textValueChangeListner}'

In my scenario it is necessary that page developer may or may not supply the "textValueChangeListner" to the composite component. How can I achieve that ?

Upvotes: 1

Views: 2972

Answers (2)

cubbuk
cubbuk

Reputation: 7920

You have two options here: First one is the easy way, just render another input text without having a valueChangeListener if the user didn't supply Value Change listener.

<ice:inputText
                  value="#{cc.attrs.textValue}"
                  valueChangeListener="#{cc.attrs.textValueChangeListener}"
                  rendered="#{!empty cc.attrs.textValueChangeListener}"/>

If you need to have a valueChangeListener in any case then apply an default value for the attribute:

<composite:attribute name="textValueChangeListener"
                       method-signature="void valueChanged(javax.faces.event.ValueChangeEvent)"
                     required="false"
                     default="#{cc.valueChangedListener}" />

For doing this you need to bind your composite component to a backing bean. And you need to define components' backing bean type through its interface declaration like this:

<composite:interface componentType="yourComponentBean">
<composite:attribute name="textValueChangeListener"
                       method-signature="void valueChanged(javax.faces.event.ValueChangeEvent)"
                     required="false"
                     default="#{cc.valueChangedListener}" />
</composite:interface>

And here is yourComponentBean which implements the default ValueChangedListener.

@FacesComponent("yourComponentBean")
public class YourComponentCC extends UINamingContainer
{
    public void valueChangedListener(ValueChangeEvent ev)
    {
       ....
    }
}

Btw cc is a shortcut in EL to access backing bean that is defined as the componentType in your component. so cc.valueChangedListener will call valueChangedListener method defined in YourComponentCC class.

Upvotes: 2

BalusC
BalusC

Reputation: 1108782

Rename the attribute to valueChangeListener and use targets attribute,

<composite:attribute name="valueChangeListner"
                     method-signature="void valueChanged(javax.faces.event.ValueChangeEvent)" 
                     targets="text" />

where text is the ID of the target input component,

<ice:inputText id="text" ... />

and remove the valueChangeListener from it.

Upvotes: 2

Related Questions