Hello I want to implement a CC similar which implements a selection attribute. This is similar to to Primefaces instant row selection <p:dataTable selection="#{bean.user}" .../>.
This are the relevant definitions in the composite:
<composite:interface componentType="my.CcSelection">
<composite:attribute name="actionListener" required="true"
method-signature="void listener(javax.faces.event.AjaxBehaviorEvent)"/>
<composite:attribute name="selection"/>
</composite:interface>
<composite:implementation>
...
<ui:repeat var="item" value="#{cc.attrs.data}">
<p:commandLink actionListener="#{cc.actionListener(item)}"/>
</ui:repeat>
...
</composite:implementation>
The actionListener-method in the backing bean is the following:
public void actionListener(MyObject object)
{
logger.info("ActionListener "+object); //Always the correct object
FacesContext context = FacesContext.getCurrentInstance();
Iterator<String> it = this.getAttributes().keySet().iterator();
while(it.hasNext()) { //Only for debugging ...
logger.debug(it.next());
}
// I want the set the value here
ValueExpression veSelection = (ValueExpression)getAttributes().get("selection");
veSelection.setValue(context.getELContext(), object);
// And then call a method in a `@ManagedBean` (this works fine)
MethodExpression al = (MethodExpression) getAttributes().get("actionListener");
al.invoke(context.getELContext(), new Object[] {});
}
If I use my CC with a value-expression for selection (e.g. selection="#{testBean.user}", veSelection is null (and selection is not printed in the debug-iteration) and I get a NPE. If I pass a String (e.g. selection="test", the attribute selection is available in the debug-iteration, but (of course) I get a ClassCastException:
java.lang.String cannot be cast to javax.el.ValueExpression
How can I provide a actionListener and a selection attribute to my component, and set the selected value in the first step and then invoke the actionListener?
As to the debug-iteration, you won’t see value expressions in keyset nor entryset of
UIComponent#getAttributes(). This is also explicitly mentioned in javadoc. In other words, that map contains only entries having static values. Only if you explicitly callget()on the map, and the underlying attribute is a value expression, then it will actually invoke it and return the evaluated value.In order to get a value expression, use
UIComponent#getValueExpression()instead.As to the method expression, well, that’s the easiest if your composite extends from
UICommand, but this is in your particular case plain clumsy. Just set the target of the listener method to the command link and use<f:setPropertyActionListener>to set the desired property in the bean. This way the backing component is unnecessary.