I'm implementing a composite component and I found a issue which I didn't find a solution.
I specified its attributes that can or not be passed by the page author, but I couldn't specify a method attribute (a method expression to Action) that, if it wasn't passed, the composite component doesn't use the method attribute in the composite:implementation tag.
Here my code:
<composite:interface>
<composite:attribute name="namePrompt" required="true"/>
<composite:attribute name="actionMethod" method-signature="java.lang.String action()" required="false"/>
<composite:attribute name="showComponent" default="false"/>
</composite:interface>
<composite:implementation>
<div>
<p:commandLink actionListener="#{cc.attrs.actionMethod}"
rendered="#{cc.attrs.showComponent}"
>
<h:outputText value="#{cc.attrs.namePrompt}"/>
</p:commandLink>
</div>
</composite:implementation>
When using it, I didn't specify the "actionMethod" attribute. Like this:
<util:foo namePrompt="SomeName" showComponent="true"/>
But I get the error message:
javax.faces.FacesException: Unable to resolve composite component from using page using EL expression '#{cc.attrs.actionMethod}'
Is there a way to do this?
You will have to create two p:commandLink
elements and render them conditionally according to definition of your parameter:
<p:commandLink actionListener="#{cc.attrs.actionMethod}" rendered="#{!empty cc.getValueExpression('actionMethod') and cc.attrs.showComponent}">
<h:outputText value="#{cc.attrs.namePrompt}"/>
</p:commandLink>
<p:commandLink rendered="#{empty cc.getValueExpression('actionMethod')}">
<h:outputText value="#{cc.attrs.namePrompt}"/>
</p:commandLink>
Change the method signature return type to java.lang.Object and add "null" as the default value.
<composite:interface>
<composite:attribute name="namePrompt" required="true"/>
<composite:attribute name="actionMethod" method-signature="java.lang.Object action()" required="false" default="null"/>
<composite:attribute name="showComponent" default="false"/>
</composite:interface>
<composite:implementation>
<div>
<p:commandLink actionListener="#{cc.attrs.actionMethod}"
rendered="#{cc.attrs.showComponent}"
>
<h:outputText value="#{cc.attrs.namePrompt}"/>
</p:commandLink>
</div>
</composite:implementation>
Without method:
<util:foo namePrompt="SomeName" showComponent="true"/>
With method:
<util:foo actionMethod="#{someBean.someMethod()}" namePrompt="SomeName" showComponent="true"/>
An other solution is to create an own component type, with a action method. Example:
<composite:interface componentType="myButton">
<composite:attribute name="namePrompt" required="true"/>
<composite:attribute name="actionMethod" method-signature="java.lang.String action()" required="false"/>
<composite:attribute name="showComponent" default="false"/>
</composite:interface>
<composite:implementation>
<div>
<p:commandLink actionListener="#{cc.action()}" rendered="#{cc.attrs.showComponent}">
<h:outputText value="#{cc.attrs.namePrompt}"/>
</p:commandLink>
</div>
</composite:implementation>
And the componentType has to look like:
@FacesComponent("myButton")
public class MyButton extends UINamingContainer {
public MyButton () {
}
public String action() {
MethodExpression me = (MethodExpression) this.getAttributes().get("actionMethod");
if (me != null) {
try {
Object result = me.invoke(FacesContext.getCurrentInstance().getELContext(), null);
if (result instanceof String) {
return (String) result;
}
} catch (ValidatorException ve) {
throw ve;
}
}
return null;
}
}
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