Disable Autocomplete if completeMethod not set - jsf

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?

Related

Native JSF color input widget

According to Mozilla's Developer Network, there is an HTML input element with type="color" since HTML 4.01. It can be used in a form like this:
<form>
<input type="color"/>
</form>
I tested this with recent browsers (Firefox 52, Chromium 65 and Opera 49) and all were working well with plain HTML. They provide a button and on click a popup-window is opened to select a color.
Now the question: how can I use this color input with JSF without a third-party library?
I couldn't find any suitable component for neither JSF 2.2 nor 2.3. I know there is PrimeFaces <p:colorPicker> and there are probably other third-party components as well. But I need/want plain JSF/Mojarra.
I found this answer, which describes the use of passthrough attributes. With this, it is actually quite simple to create a basic composite-component which does exactly what I need:
<ui:component xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:a="http://xmlns.jcp.org/jsf/passthrough"
xmlns:cc="http://xmlns.jcp.org/jsf/composite">
<cc:interface>
<cc:attribute name="value" type="java.lang.String" required="true" />
<cc:clientBehavior name="clientEvent" targets="colorInput" event="change" />
</cc:interface>
<cc:implementation>
<h:inputText id="colorInput" a:type="color" value="#{cc.attrs.value}" />
</cc:implementation>
</ui:component>
(See also BalusC's answer on details about <cc:clientBehavior>.)

Passing a converter to a composite component

After some experimenting and reading up, I found the same solution as How to reference component inside a composite component when using a converter
The problem however is that I have two IDs for the valueholder and according to the documentation I could use id1,id2 as targets but that doesn't work.
This is my composite component:
<cc:interface>
<cc:attribute name="id" required="true"/>
<cc:attribute name="value" required="true"/>
<cc:attribute name="editable" required="true"/>
<cc:editableValueHolder name="element" targets="input,output"/>
</cc:interface>
<cc:implementation>
<h:inputText value="#{cc.attrs.value}" id="input" rendered="#{cc.attrs.editable}"/>
<h:outputText value="#{cc.attrs.value}" id="output" rendered="#{not cc.attrs.editable}"/>
</cc:implementation>
And this is how I intend to use the CC:
<r:inputText editable="#{registrationBean.editable}" id="dateOfBirth"
value="#{registrationBean.dateOfBirth}">
<f:convertDateTime pattern="dd-MM-yyyy" type="date" for="element" />
</r:inputText>
I originally tried inserting the converter via insertChildren and via a facet but none worked.
target needs to be space separated not comma separated
If present, this must be a space (not tab) separated list of client
ids (relative to the top level component) of components within the
section. Space is used as the delimiter for
compatibility with the IDREFS and NMTOKENS data types from the XML
Schema.
JSF2.2 docs

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

How to add documentation to attribute of composite component

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." />

Passing markup via composite components attributes

Is there a way to pass markup (in opposite to plain text) via composite
component's attributes? Simply <composite:insertChildren> won't suffice,
since the component rely on distinct text parameters. Passing tags via
attributes as described in Include sub-element inside JSF 2.0 component does not work (invalid attribute content).
You need to declare it as <cc:facet> and render it as <cc:renderFacet>:
<cc:interface>
<cc:facet name="foo" />
</cc:interface>
<cc:implementation>
<cc:renderFacet name="foo" />
</cc:implementation>
This way you can specify it using <f:facet>:
<my:composite>
<f:facet name="foo">
<p>Some <strong>HTML</strong> markup.</p>
</f:facet>
</my:composite>

Resources