How to add documentation to attribute of composite component - jsf

I have a composite component that looks something like this:
<composite:interface>
<composite:attribute name="confirmUnload" type="java.lang.Boolean" default="false" />
<composite:attribute name="showLoader" type="java.lang.Boolean" default="true" />
<composite:attribute title="test test" name="menuFormIds" type="java.lang.String" default="menuForm" />
<composite:attribute name="unloadMessage" type="java.lang.String" default="You have unsaved data" />
</composite:interface>
<composite:implementation>
<div title="unloadEventComponent">...</div>
</composite:implementation>
When using this component in a page, eclipse autocomplete will help out with the attributes. However, sometimes it's difficult to understand what the attribute does without looking at the code, which does not help the user experience.
Is there any way to have attribute descriptions added to a composite component in a way that it shows up in eclipse autocomplete?
PrimeFaces components usually have descriptions when selecting an attribute, but they use custom components instead of composites.

For that, the shortDescription attribute should be used. E.g.
<composite:attribute name="confirmUnload" type="java.lang.Boolean" default="false"
shortDescription="Set to true to enable the confirm unload message. Defaults to false." />

Related

Disable Autocomplete if completeMethod not set

I basically have this composite:
<cc:interface>
<cc:attribute name="value" />
<cc:attribute name="itemLabel" type="java.lang.String"/>
<cc:attribute name="itemValue" />
<cc:attribute name="completeMethod" method-signature="java.util.List oncomplete(java.lang.String))"/>
</cc:interface>
<cc:implementation>
<p:autoComplete
value="#{cc.attrs.value}"
completeMethod="#{cc.attrs.completeMethod}"
var="#{cc.attrs.var}"
itemLabel="#{cc.attrs.itemLabel}"
itemValue="#{cc.attrs.itemValue}"
pt:readonly="#{empty cc.getValueExpression('completeMethod')}" />
</cc:implementation>
I want to make sure that autocomplete is readonly when completeMethod is not defined. Doing this, it always returns true. I guess it is a problem about build/render time. I quote:
"Passthrough elements" is a JSF 2.2 specific term for declaring JSF
components as "plain" HTML5 elements which should be automatically
converted to real JSF components during view build time, when an
"identifying attribute" is present in the plain HTML5 markup.
Is there a way to work this around?

Reference dynamic Id in JSF composite components

I've been having some trouble to reference Id with composite components in JSF like the example:
`<composite:interface>
<composite:attribute name="id" required="true"/>
</composite:interface>
<composite:implementation>
<h:inputText id="#{cc.attrs.id}" value="Any"
</composite:implementation>
`
And when I try to pass the Id as param, I can't reference it from a "for" for example from an outputLabel, it seems this kind of composite components in JSF does not support dynamic Ids, what is the solution for it?
Thanks in advance.

Using id-attribute in JSF 2 composite component with targets

I am trying to create a JSF 2.1 composite component for a button:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
xmlns:c="http://java.sun.com/jstl/core">
<composite:interface>
<composite:attribute name="id" required="true" type="java.lang.String" />
<composite:attribute name="label" required="true" type="java.lang.String" />
<composite:attribute name="action" method-signature="java.lang.String action()" targets="#{cc.attrs.id}" />
</composite:interface>
<composite:implementation>
<a4j:commandLink id="#{cc.attrs.id}">
<span style="linkButton"><h:outputText value="#{cc.attrs.label}" /></span>
</a4j:commandLink>
</composite:implementation>
</html>
The problem I have with this code is that it gives the following exception when the page is rendered:
java.lang.ClassCastException: javax.faces.component.UINamingContainer cannot be cast to javax.faces.component.ActionSource2
at com.sun.faces.application.view.FaceletViewHandlingStrategy$MethodRetargetHandlerManager$ActionRegargetHandler.retarget(FaceletViewHandlingStrategy.java:1536)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.retargetMethodExpressions(FaceletViewHandlingStrategy.java:689)
at com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.applyNextHandler(CompositeComponentTagHandler.java:201)
at org.richfaces.view.facelets.html.BehaviorsAddingComponentHandlerWrapper.applyNextHandler(BehaviorsAddingComponentHandlerWrapper.java:53)
at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:196)
...
When I replace the #{cc.attrs.id} in id and targets attribute with a defined String like myId then the component works as expected but this makes it not reusable in the same page and thus eliminates the wohle sense in creating a composite component in the first place.
Did I miss anything here?
In the JSF component tree, the #{cc.attrs.id} is already used by <cc:implementation> itself. You're not supposed to reuse any used component ID on another component. Your concrete functional requirement is unclear, the complaint "not reusable in the same page" makes really no sense as it works perfectly fine (have you actually tried it and investigated the produced HTML output?), so it's hard to understand what problem exactly you're facing. Perhaps you completely overlooked that composite components implicitly inherit from NamingContainer and already prepend their own id to those of children, like as <h:form>, <h:dataTable>, etc also do?
If your sole requirement is being able to reference the composite component from outside by ajax as in <f:ajax render="compositeId" />, then you need to wrap the body of <cc:implementation> in a plain vanilla HTML <span> or <div> as follows with the #{cc.clientId} instead:
<div id="#{cc.clientId}">
See also:
Rerendering composite component by ajax

What is f:attribute used for in this example?

I'm trying to understand what a JSF snippet does. It goes something like this
<composite:interface>
<composite:attribute name="field" />
<composite:attribute name="value" default=""/>
[...]
</composite:interface>
<composite:implementation>
<ui:fragment rendered="some_logic_here">
<h:outputText value="#{cc.attrs.value}">
<f:attribute name="value" value="#{cc.attrs.field.value}"/>
</h:outputText>
</ui:fragment>
</composite:implementation>
The field attribute refers to a bean member that has getValue() / setValue() accessors (for a string).
The value attribute is a string that comes from elsewhere.
From what I understand, the output's value is initially set to the (static) value attribute: value="#{cc.attrs.value}", then the <f:attribute> tag sets something to the "dynamic" value retrieved from the "field" bean.
How does this work out? Does the "dynamic" value override the static one? Always?
As you guessed, this does indeed exactly the same as:
<h:outputText value="#{cc.attrs.field.value}" />
In other words, the original developer didn't thought out it very well, or was fiddling until it started to work like magic, or perhaps had a short on coffee, or smoked something bad while developing.

Conditionally render element's attribute in a composite component

I have the following composite component:
<?xml version="1.0" encoding="UTF-8"?>
<ui:component xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
<composite:attribute required="true" name="field" />
<composite:attribute required="true" name="value" />
<composite:attribute required="false" name="size"/>
</composite:interface>
<composite:implementation>
...
<div class="wrapper">
<h:inputText value="#{cc.attrs.value}"
id="#{field.id}"
rendered="#{field.rendered}"
size="#{cc.attrs.size}">
</h:inputText>
<h:messages for="#{field.id}" styleClass="errorMessage"/>
</div>
...
</composite:implementation>
</ui:component>
The problem is that when I'm using this component without setting its size attribute, it still gets rendered as size=0 in the html input element.
What I want is to render the nested h:inputText's attribute only if it has a valid value (eg. not empty). Alternatively, I'd like to expose all attributes of the nested element if they are not overridden explicitly.
How would it be possible?
You can use JSTL <c:if> to build the view conditionally and <f:attribute> to specify an attribute separately:
<h:inputText ...>
<c:if test="#{not empty cc.attrs.size}">
<f:attribute name="size" value="#{cc.attrs.size}" />
</c:if>
</h:inputText>
An alternative is to specify a default for the composite component attribute:
<cc:attribute name="size" required="false" default="10" />
Additional to BalusC's post:
You must use
type="int" in the cc:attribute-tag :
cc:attribute name="maxlength" type="int"
I believe there is an alternate method for accessing attributes. I've used this with JSF 2 when accessing an attribute named with a java reserved keyword.
{cc.attrs['size']}

Resources