Composite JSF 2.2 component with validation message not displayed - jsf

I working on custom JSF 2.2 components with corporate design.
I have a problem with input text.
The problem is that if I use my component and want to specify <h:message for="id_of_component"/> its not work. Because the id of component is different.
<h:message for="input"/>
<custom:input id="input" required="true"/>
If i specify it inside component it works but it's not what I want. It should be flexible in case anyone want to use message on diferent place than I specify in component.
Component definition (with message):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:p="http://xmlns.jcp.org/jsf/passthrough">
<!-- INTERFACE -->
<cc:interface name="input" expert="true">
<cc:attribute name="id" required="false"/>
<cc:attribute name="label" />
<cc:attribute name="value" />
<cc:attribute name="title" />
<cc:attribute name="readonly" default="false" type="java.lang.Boolean" />
<cc:attribute name="required" default="false" type="java.lang.Boolean" />
<cc:attribute name="rendered" default="true" type="java.lang.Boolean" />
<cc:attribute name="placeholder" type="java.lang.String"/>
<cc:clientBehavior name="click" targets=":#{cc.id}" event="click" default="true"/>
<cc:clientBehavior name="change" targets=":#{cc.id}" event="change" default="true"/>
<cc:clientBehavior name="blur" targets=":#{cc.id}" event="blur" default="true"/>
<cc:clientBehavior name="keyup" targets=":#{cc.id}" event="keyup" default="true"/>
</cc:interface>
<cc:implementation>
<h:panelGrid rendered="#{cc.attrs.rendered}" columns="2" id="panel" styleClass="customInputWrapper">
<h:outputLabel title="#{cc.attrs.title}"
value="#{cc.attrs.label}#{cc.attrs.required ? ' *' : ''}" for="#{cc.attrs.id}" />
<h:inputText id="#{cc.attrs.id}" styleClass="customInput" value="#{cc.attrs.value}" p:placeholder="#{cc.attrs.placeholder}" readonly="#{cc.attrs.readonly}" title="#{cc.attrs.title}" required="#{cc.attrs.required}"/>
<h:message for="#{cc.attrs.id}" />
<h:outputStylesheet library="custom" name="customComponentsStyle.css"/>
</h:panelGrid>
</cc:implementation>
</html>
Do you have any solution how to solve this problem?

Related

Delegate actionsource to inner composite component

Please help to find out the problem.
I have two composite components:
ajaxCommandButton:
<cc:interface>
<cc:actionSource name="ajaxAction" targets="ajaxCmd" />
<cc:attribute name="action" targets="ajaxCmd" method-signature="void action()" />
<cc:attribute name="value" />
<cc:attribute name="title" />
</cc:interface>
<cc:implementation>
<h:commandButton value="#{cc.attrs.value}" id="ajaxCmd"
title="#{cc.attrs.title}" >
<f:ajax />
</h:commandButton>
</cc:implementation>
and treeItem:
<cc:interface>
<cc:actionSource name="itemAction" targets="ajaxAction" />
</cc:interface>
<cc:implementation>
<ccb:ajaxCommandButton value="test" action="#{action()}" id="ajaxAction">
<f:setPropertyActionListener for="ajaxAction" value="#{value}" target="#{beanProperty}" />
</ccb:ajaxCommandButton>
</cc:implementation>
and usage from ui:composition
<ccb:treeItem>
<f:setPropertyActionListener for="ajaxAction" value="#{value}" target="#{beanProperty}" />
</ccb:treeItem>
What right way to set actionSource from ui:composition to ccb:ajaxCommandButton ?
Thanks in advance!

Label of composite component and o:validateMultipleFields

I have the following composite component, and I want to use o:validateMultipleFields (o:validateAllOrNone more specifically).
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<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:p="http://primefaces.org/ui"
xmlns:composite="http://java.sun.com/jsf/composite"
>
<composite:interface>
<composite:attribute name="target" />
<composite:attribute name="label"/>
<composite:attribute name="value" />
<composite:attribute name="required" />
<composite:attribute name="size" />
<composite:attribute name="disabled" />
<composite:attribute name="styleInput" required="false" />
<composite:editableValueHolder name="input" targets="input" />
<composite:clientBehavior name="change" event="change" targets="#{cc.attrs.target}" />
<composite:clientBehavior name="keypress" event="keypress" targets="#{cc.attrs.target}" />
</composite:interface>
<composite:implementation>
<p:outputLabel id="label" for="input" value="#{cc.attrs.label}" />
<h:panelGrid columns="3">
<p:inputText id="input" value="#{cc.attrs.value}"
style="#{cc.attrs.styleInput}" size="#{cc.attrs.size}"
disabled="#{cc.attrs.disabled}" required="#{cc.attrs.required}">
</p:inputText>
<p:message for="input" display="icon">
<p:effect type="pulsate" event="load" delay="500" />
</p:message>
</h:panelGrid>
</composite:implementation>
</html>
The validation is working as expected, but the labels of the components specified on the components property are no showing. Instead it's showing the components id's.
<cetcomp:editar id="origem" label="Origem" size="10" />
<cetcomp:editar id="cst" label="CST" size="10" />
<o:validateAllOrNone id="origemCst" components="origem:input cst:input" showMessageFor="origem:input" />
The ValidateMultipleFields extracts the labels from the label attribute of the physical input components. Exactly those labels which would be used in standard JSF validation, too. You indeed have none, they are only set on the <p:outputLabel>.
Add them accordingly:
<p:inputText ... label="#{cc.attrs.label}">
An alternative is to use <o:outputLabel> instead of <p:outputLabel> as the OmniFaces one would automatically copy the label to the associated input component.
<o:outputLabel ... for="input" value="#{cc.attrs.label}" />
<p:inputText id="input" ... />
Update: it turns out that it actually still didn't work. The #{cc} wasn't available while ValidateMultipleFields is extracting the labels. This was fixed as per issue 134 and it will be available in OmniFaces 2.1.

How to pass a validator to a inputtext in a nested(!) composite component in JSF 2

I have the following problem with nested composite components and passing validators to a inputtext in a nested component:
The wrapper custom component (wrapper.xhtml):
<cc:interface>
<cc:attribute name="value" required="false" />
</cc:interface>
<cc:implementation>
<h:panelGroup>
<h:outputLabel value="TEST:"/>
<temptest:input value="#{cc.attrs.value}">
<cc:insertChildren/>
</temptest:input>
</h:panelGroup>
</cc:implementation>
The nested custom component (input.xhtml):
<cc:interface>
<cc:attribute name="value" required="false" />
<cc:editableValueHolder name="input" targets="input" />
</cc:interface>
<cc:implementation>
<h:inputText value="#{cc.attrs.value}" id="input" >
<cc:insertChildren/>
</h:inputText>
</cc:implementation>
The trial to pass a validator to the nested custom component (pageXYZ.xhtml):
<h:form>
...
<temptest:wrapper value="#{bean.value}">
<f:validateRequired for="input"/>
</temptest:wrapper>
<!-- this works:
<temptest:input value="#{bean.value}">
<f:validateRequired for="input"/>
</temptest:input> -->
<h:message for="input"/>
...
</h:form>
Is there a way to pass (one or more) validators to a nested custom component?

Use Omnifaces Validator in a composition component with the "for" tag

I want to use the o:validator tag from the omnifaces library for a composition component:
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core" xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui"
xmlns:pe="http://primefaces.org/ui/extensions">
<cc:interface>
<cc:attribute name="disabled" />
<cc:attribute name="label" />
<cc:attribute name="validatorMessage" />
<cc:attribute name="required" />
<cc:attribute name="value" required="true" />
<cc:editableValueHolder name="date" targets="textfield"/>
</cc:interface>
<cc:implementation>
<p:outputLabel id="label" for="textfield" value="#{cc.attrs.label}" rendered="#{cc.attrs.label!=null}" />
<p:inputText id="textfield" value="#{cc.attrs.value}" styleClass="dateInputField" required="#{cc.attrs.required}" disabled="#{cc.attrs.disabled}">
<f:convertDateTime locale="de_DE" type="date" />
<!-- some other stuff... -->
</p:inputText>
<p:watermark for="textfield" value="TT.MM.JJJJ" />
<cc:insertChildren/>
</cc:implementation>
The validator gets called like this:
<o:validator validatorId="customGreaterThanValidator" compareTo="#{bean.date}" validatorMessage="given date must be later than #{bean.date}" for="date"/>
But unfortunatly it seems that the validator tag from omnifaces ignores the "for" Attribute. With the original validator tag from JSF the "for" tag works, but not if the value of the "compareTo" tag is a ValueExpression.
I tried to implement a custom taghandler, but that didn't work either.
This is indeed not supported in the current 1.3 <o:validator> (nor <o:converter>). It will come in future 1.4 as per issue 126 (where you can download the snapshot).
The key is to change TagHandler to ValidatorHandler and ConverterHandler respectively so that the TagHandlerDelegate can do its job for composites.

Required message for pe:inputNumber

I use composite component which has InputNumber from Primefaces extensions in its basis. I've set required attribute to true and message is not shown. Also I don't have * mark which indicates that the field is required.
Here is the code:
<p:outputLabel for="maxvrednost" value="#{resources['skale.maxvrednost']}" />
<asw:inputDecimal id="maxvrednost" bean="#{attrsBean}" column="maxvrednost" required="true" disabled="#{tip == 'brisanje'}" value="#{dto.maxvrednost}"/>
<p:message for="maxvrednost" display="icon" />
Code for composite component is:
<cc:interface>
<cc:attribute name="bean" required="true" type="asw.iis.common.ui.beans.CommonListBackingBean" />
<cc:attribute name="column" required="true" type="java.lang.String" />
<cc:attribute name="value" required="true" type="java.lang.Object" />
<cc:attribute name="disabled" default="false" required="false" type="java.lang.Boolean" />
<cc:attribute name="title" required="false" type="java.lang.String" default=""/>
</cc:interface>
<cc:implementation>
<pe:inputNumber emptyValue="" style="text-align: right;" value="#{cc.attrs.value}" required="#{cc.attrs.required}"
decimalSeparator="#{applicationPropertiesBean.decimalSeparator}" disabled="#{cc.attrs.disabled}"
decimalPlaces="#{cc.attrs.bean.findNumberOfDecimalPlaces(cc.attrs.column)}" title="#{cc.attrs.title}"
thousandSeparator="#{applicationPropertiesBean.groupSeparator}">
</pe:inputNumber>
</cc:implementation>
Not a 100% proper solution but it works for me:
<composite:interface >
<composite:attribute name="value" required="false" type="java.lang.String" default=""></composite:attribute>
<composite:attribute name="update" required="false" type="java.lang.String" default=""></composite:attribute>
<composite:attribute name="process" required="false" type="java.lang.String" default=""></composite:attribute>
<composite:attribute name="requiredMessage" required="false" type="java.lang.String" default=""></composite:attribute>
<composite:attribute name="decimalPlaces" required="false" type="java.lang.Integer" default="0"></composite:attribute>
<composite:editableValueHolder name="value" targets="num"></composite:editableValueHolder>
<composite:
</composite:interface>
<composite:implementation>
<div id="#{cc.clientId}">
<pe:inputNumber id="num" roundMethod="S" decimalPlaces="#{cc.attrs.decimalPlaces}" symbol="#{applicationBean.currentCurrencySymbol}"
minValue="0" required="true" requiredMessage="#{cc.attrs.requiredMessage}"
value="#{cc.attrs.value}"></pe:inputNumber>
</div>
</composite:implementation>
Use as follows:
<p:outputLabel value="Enter Amount" for="amt:num"></p:outputLabel>
<p:message for="amt:num"></p:message>
<comp:InputCurrency id="amt" roundMethod="S" decimalPlaces="0" symbol="#{applicationBean.currentCurrencySymbol}"
minValue="1" requiredMessage="#{loc._('Please enter amount to withdraw!')}"
value="#{myBean.amount}"></comp:InputCurrency>
Note that 'required' attribute is hardcoded to 'true'. If I define composite component attribute 'required' and copy the value to inputNumber 'required' property it behaves as required, but does not render the '*' mark on the label. This happens because inputNumber's 'required' attribute has not been set at render time, comes back as 'false' - not sure why, didnt have time to dig into this.

Resources