Read/Write attributes in Composite component - jsf-2

I am writing a JSF datepicker composite component that is backed by jquery-ui's datepicker.(I don't have the option of using component libraries)
I have gotten the functionality to work, but I am now trying to simplify the component's interface by removing unnecessary attributes.
One of the attributes exposed by my component is called "value". I expect the user of the component to provide an el reference here eg.
#{myCarBean.selectedCar}
What I have noticed is that the component only ever seems to read the attribute's value. The setter never seems to get invoked.
I managed to get around this by exposing this method as a clientBehaviour .
But now I have an actionListener that is invoked through this clientBehaviour(to set the value) as well as the "value" attribute which reads the value from #{cc.attrs.values}.
How can I have a single attribute that can both read/write the "value" attribute to the underlying managedBean provided by the using page?
Here is the code:
<ui:component xmlns="http://www.w3.org/1999/xhtml" xmlns:util="http://discovery.co.za/mytags" xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:cc="http://java.sun.com/jsf/composite">
<cc:interface componentType="modal">
<cc:attribute name="value" type="java.util.Date" shortDescription="An El expression representing the managed bean field to which the selected date will be wired."></cc:attribute>
<cc:attribute name="minYear" type="java.lang.Integer" shortDescription="An El expression representing a managed bean field which should return an Integer indicating the year component of the minDate"></cc:attribute>
<cc:attribute name="minMonth" type="java.lang.Integer" shortDescription="An El expression representing a managed bean field which should return an Integer indicating the month component of the minDate.(January is 0)"></cc:attribute>
<cc:attribute name="minDay" type="java.lang.Integer" shortDescription="An El expression representing a managed bean field which should return an Integer indicating the day component of the minDate."></cc:attribute>
<cc:attribute name="maxYear" type="java.lang.Integer" shortDescription="An El expression representing a managed bean field which should return an Integer indicating the year component of the maxDate"></cc:attribute>
<cc:attribute name="maxMonth" type="java.lang.Integer" shortDescription="An El expression representing a managed bean field which should return an Integer indicating the month component of the maxDate"></cc:attribute>
<cc:attribute name="maxDay" type="java.lang.Integer" shortDescription="An El expression representing a managed bean field which should return an Integer indicating the day component of the maxDate"></cc:attribute>
<cc:attribute name="render" type="java.lang.String" />
<cc:clientBehavior name="change" targets="#{cc.clientId}:dateInput" event="change" />
</cc:interface>
<cc:implementation>
<div id="#{cc.clientId}">
<h:inputText id="dateInput" value="#{cc.attrs.value}" styleClass="jquery-datepicker"
onclick="modifyDatePickerOptions('#{cc.attrs.clientId}', #{cc.attrs.minYear}, #{cc.attrs.minMonth}, #{cc.attrs.minDay}, #{cc.attrs.maxYear}, #{cc.attrs.maxMonth}, #{cc.attrs.maxDay} );">
<f:ajax execute="#form" event="change" render="#{cc.attrs.render}" />
</h:inputText>
</div>
</cc:implementation>
And the using page :
<h:form id="datePickerForm">
<my:datepicker render=":datePickerForm:datePickerAjax" value="#{datePickerBean.selectedDate}" minYear="1999" minMonth="0" minDay="1" maxYear="2019" maxMonth="0" maxDay="1">
<f:ajax event="change" listener="#{datePickerBean.selectedDate}" />
</my:datepicker>
<h:panelGroup id="datePickerAjax" layout="block">
<br />
<b><h:outputText value="You selected : #{datePickerBean.selectedDate}" rendered="#{datePickerBean.selectedDate != null}" /></b>
</h:panelGroup>
</h:form>

You need to add a converter to your inputText field. You can nest an <f:convertDateTime/> tag in your inputText to achieve this. See convertDateTime for all the available attributes.

Related

Passing paramater to validator of composite component

I am using Mojarra 2.3.0.
I have a composite component which contains an inputText. I want to be able to validate this inputText using a FacesValidator. Furthermore I want to pass certain parameters to the validator.
My Composite component is defined this way:
<composite:interface>
...
<composite:editableValueHolder name="inputValidator" targets="value" />
...
</composite:interface>
<composite:implementation>
...
<h:panelGroup layout="block" styleClass="col-sm-10">
<h:inputText id="value"
disabled="#{cc.attrs.disabled}"
value="#{cc.attrs.value}"
styleClass="form-control"
required="#{cc.attrs.required}"
onchange="#{cc.attrs.onChange}"
/>
</h:panelGroup>
...
</composite:implementation>
I use the component this way and declared a f:validator and f:attribute (which should be passed to the validator)
<uiComps:field labelText="add language"
id="languages"
autocompleteValues="#{ocrEngineViewModel.getAllSupportedLanguages()}" >
<f:ajax event="onChange" listener="#{ocrEngineViewModel.updateSelectedLanguages}" render="newParameter:languages:value newParameter:usedLanguages" />
<f:validator validatorId="OcrLanguageValidator" for="inputValidator" />
<f:attribute name="allSupportedLanguages" value="#{ocrEngineViewModel.allSupportedLanguages}"/>
</uiComps:field>
<h:message for="languages" />
My validator looks like this:
#FacesValidator("OcrLanguageValidator")
public class OcrLanguageValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
Object allSupportedLanguages = component.getAttributes().get("allSupportedLanguages");
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "lala", "not good"));
}
}
There are two problems:
The parameter "allSupportedLanguages" (which is a List<String>) is null when I try to retrieve it in the validator.
The ValidationException which holds a FaceMessage is not displayed in the message area for the component. I don't see any information about the message on the page.
Update:
Instead of the composite component I put the code directly into my page.
<h:panelGroup layout="block" styleClass="col-sm-10">
<h:inputText id="value" styleClass="form-control">
<f:ajax event="change" listener="#{ocrEngineViewModel.updateSelectedLanguages}" render="newParameter:languages:value newParameter:usedLanguages" />/>
<f:validator validatorId="OcrLanguageValidator"/>
<f:attribute name="allSupportedLanguages" value="#{ocrEngineViewModel.allSupportedLanguages}"/>
</h:inputText>
</h:panelGroup>
This works and I see the attribute in the validator. So I guess the problem lies in the usage of the composite component.
Update2:
I was able to solve the validation error message problem. I placed the <h:message for="value"/> inside the composite component.

How work auto complite custom component?

A have found sample on internet(IBM site http://www.ibm.com/developerworks/web/library/j-jsf2fu-0410/index.html#listing1) and on some book that with JSF can make auto complete drop down list. Like on google search page. The main point of this is in using composite component page. It look like:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite">
<!-- INTERFACE -->
<composite:interface>
<composite:attribute name="value" required="true"/>
<composite:attribute name="completionItems" required="true"/>
</composite:interface>
<!-- IMPLEMENATION -->
<composite:implementation>
<div id="#{cc.clientId}">
<h:outputScript library="javascript"
name="prototype-1.6.0.2.js" target="head"/>
<h:outputScript library="javascript"
name="autoComplete.js" target="head"/>
<h:inputText id="input" value="#{cc.attrs.value}"
onkeyup="com.corejsf.updateCompletionItems(this, event)"
onblur="com.corejsf.inputLostFocus(this)"
valueChangeListener="#{autocompleteListener.valueChanged}"/>
<h:selectOneListbox id="listbox" style="display: none"
valueChangeListener="#{autocompleteListener.completionItemSelected}">
<f:selectItems value="#{cc.attrs.completionItems}"/>
<f:ajax render="input"/>
</h:selectOneListbox>
<div>
</composite:implementation>
</ui:composition>
My questions are:
Why we use ui:composition tags with out any parameters.
We have in h:inputText defined valueChangeListener, realized over backend class which has method public void valueChanged(ValueChangeEvent e) with these two lines
UIInput input = (UIInput) e.getSource();
UISelectOne listbox = (UISelectOne) input.findComponent("listbox");
If (UIInput)e.get source return component inputText with id="name". How possible next line
UISelectOne listbox = (UISelectOne)input.findComponent("listbox");
For the first question: <ui:composition template="..."> renders the content's of this tag into the specified template. Since you have no template here, the attribute isn't needed.
For the second question: findComponent searches for the given id in the enclosing NamingContainer, which is your composite component (check the Javadoc for the full algorithm). It's not like jQuery where it only searches "below" the given component.

How to use Primefaces autocomplete with a POJO List and a POJO's property as selection value

In our current project we want to replace a <h:selectOneMenu> with Primefaces's <p:autocomplete>. The select items are a list of Pojos (JPA Entities). The difference to the given examples in primefaces showcases is, that we want the primary key property (id) of the entity as selection value, so it can be easily passed as view param:
<f:metadata>
<f:viewParam name="playerId" value="#{playerPreRenderViewListener.searchCriteria.playerId}" />
<f:viewParam name="year" value="#{playerPreRenderViewListener.searchCriteria.year}" />
</f:metadata>
<h:form>
<h:inputText value="#{playerPreRenderViewListener.searchCriteria.year}"/>
<p:autoComplete var="player" itemLabel="#{player.name}" itemValue="#{player.id}"
completeMethod="#{playerBean.completePlayer}" forceSelection="true"
converter="#{playerConverter}"
value="#{playerPreRenderViewListener.searchCriteria.playerId}">
</p:autoComplete>
<h:commandButton value="Submit" action="showTeam?faces-redirect=true&includeViewParams=true" />
</h:form>
Unfortunately the example above will lead to a PropertyNotFoundException:
itemLabel="#{player.name}": Property 'name' not found on type java.lang.Long'
The problem is that the var attribute is of Type Long and not Player. When using a simple <h:selectMenu> it works in conjunction with <f:selectItems>:
<f:selectItems var="player" value="#{playerBean.listPlayers}" itemLabel="#{player.name}" itemValue="#{player.id}" />
Does anybody know how to handle this issue?
You could add a backing bean method that returns the player belonging to the currently active playerId and set this currentPlayer as value attribute of your backing bean:
public Player getCurrentPlayer() {
// find player by playerId and return
}
And in the view:
<p:autoComplete var="player" itemLabel="#{player.name}" itemValue="#{player}"
completeMethod="#{playerBean.completePlayer}" forceSelection="true"
converter="#{playerConverter}"
value="#{playerPreRenderViewListener.currentPlayer}">

use validateRequired through composite component

I'm trying to forward "f:validateRequired" validator through a composite component without using required attribute.
How to get its value inside of my component ?
<aa:myComponent id="specificNotice" value="#{edit.specificNotice}">
<f:validateRequired for="specificNotice" disabled="#{empty param['form:save']}" />
</aa:myComponent>
Thanks.
The for attribute should refer the id of the input component inside the composite component implementation. The input component in turn should be declared as <cc:editableValueHolder> inside the composite component interface.
So,
<my:input value="#{bean.input}">
<f:validateRequired for="input" />
</my:input>
with
<cc:interface>
<cc:editableValueHolder name="input" />
</cc:interface>
<cc:implementation>
<h:inputText id="input" value="#{cc.attrs.value}" />
</cc:implementation>
should do.

Java facelets dynamic loading and composite component attributes

Currently I'm trying to implement webpart technology with JavaServer Faces 2.0 with Facelets view technology for educational purposes. I have created facelet templates, facelet custom components and made a few facelet "template" clients. But in one thing I'm stuck. I can't dynamically load controls and put them cc:attributes.
If I have a page for example with static text or bind it with ManagedBean the property ui:include everything works well.
<ui:define name="right-column">
right-column asd
<h:link outcome="asdf" value="link_get">
<f:param name="aa" value="123" />
<f:param name="a" value="123 dd + 20" />
</h:link>
<h:commandLink action="asdf?faces-redirect=true" value="asdf">
<f:param name="aa" value="123" />
</h:commandLink><br />
<ui:include src="./resources/Controls/CategoryTree.xhtml"/><br />
This works even if I put src with MenageBean property.
<ui:include src="#{browseProducts.incudePath}"/>
</ui:define>
Here is my facelet control (data binding is inside this control within #{TreeBean.root}:
<!-- NO INTERFACE -->
<cc:interface>
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<!-- This is a very simply scaffolding for Category Three Control.
-->
<p:tree value="#{TreeBean.root}" var="node"
expandAnim="FADE_IN" collapseAnim="FADE_OUT">
<p:treeNode>
<h:outputText value="#{node}" />
</p:treeNode>
</p:tree>
</cc:implementation>
But I have problem when ui:include points to a control with cc:attribute. I don't know how to initialize this attribute from backing bean and do "stuff".
For example I have this page:
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
template="./resources/layout/Template.xhtml"
xmlns:sc="http://java.sun.com/jsf/composite/Controls">
<ui:define name="right-column">
<sc:dummy ItemCount="10" />
<ui:include src="./resources/Controls/dummy.xhtml" />
</ui:define>
</ui:composition>
Here goes the composite control:
<cc:interface>
<cc:attribute name="ItemCount" required="true"
shortDescription="This attribute is meaningful " />
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<!-- How to pass ItemCount to my dummy bean to create so many items in
list as ItemCount value -->
<ui:repeat value="#{dummy.dummyList}" var="dummyItem">
<h:outputText value="#{dummyItem}" />
</ui:repeat>
</cc:implementation>
And backing bean code:
public ArrayList<String> getDummyList() {
//Here I try to get dummy list work.
dummyList = new ArrayList<String>(getDummyCount());
for (int i=0;i< getDummyCount();i++){
dummyList.add(i + "" + i);
}
return dummyList;
}
How can this be done?
I think you have two problems:
calling a method with parameter from a composite component
specifying some parameter to an included page
For 1., since jsf 2, you could call the method directly, specifying the parameter (which should be part of method signature):
<ui:repeat value="#{dummy.getDummyList(cc.attrs.dummyCode)}" var="dummyItem">
<h:outputText value="#{dummyItem}" />
</ui:repeat>
But I suspect you are trying to use a backing for something that it isn't designed for. Maybe you'll be interested in writing backing java code for your composite component, which is different. It's difficult to master if you are a beginner, though. I'd first try to design my pages and bean interactions differently. I don't know which problem you are trying to solve, but at first look, this solution looks too complicated.
For 2., you should have a look at ui:param. A quick google search gives me this: http://www.jsfcentral.com/articles/facelets_3.html

Resources