LocalDate (only) with primefaces calendar - jsf

I want to display a primefaces calendar element with an associated LocalDate in the Bean.
I used How to use java.time.ZonedDateTime / LocalDateTime in p:calendar as an example. The example as is works fine, BUT I don't need the time part and more importantly I don't want the time part of the calendar to be displayed.
The problem is that when I change the pattern and remove the time part:
<p:calendar id="localDate"
pattern="dd-MMM-yyyy"
value="#{bean.periodFrom}">
<f:converter converterId="localDateConverter" />
<p:ajax update="display" />
</p:calendar>
the converter is no longer called/ used at all. Which surprises me a bit.
Removing the pattern does not work neither.
Is there an alternative way to use the example without the time part? And why is the converter no longer called when I "simplify" the pattern?
JSF 2.2/ Java8/ Primefaces 6

The ajax update is not being triggered, because you didn't specify any event on which the update should be triggered.
If you do not specify any event, the default event type "change" will be used.
p:calendar triggers a "change" event, when you enter the date in the
inputText and blur
p:calendar triggers a "dateSelect" event, when you select a date in
the calendar popup
In your case, you should insert multiple event listeners:
<p:ajax update="display" />
<p:ajax event="dateSelect" update="display" />
So your code will result in:
<p:calendar id="localDate"
pattern="dd-MMM-yyyy"
value="#{bean.periodFrom}">
<f:converter converterId="localDateConverter" />
<p:ajax update="display" />
<p:ajax event="dateSelect" update="display" />
</p:calendar>
(By the way: It is not possible to combine multiple events in the same p:ajax component as you can read here https://stackoverflow.com/a/38319944/1643015)

If you used the ZonedDateTimeConverter it couldn't work at all because LocalDate is not an instance of
ZonedDateTime. That's why the converter will throw a ConverterException (because the instanceof check fails). You would see that if you insert a p:message for your p:calendar.
The used pattern "dd-MMM-yyyy" does also not work for the ZonedDateTimeConverter because this pattern neither
provides a time nor a timezone. That's why the conversion throws a DateTimeParseException and the converter throws a
ConverterException, too.
So if you want to work with LocalDate you have to implement your own converter than can deal with that class, which is very easy. Just take the ZonedDateTimeConverter and replace ZonedDateTime with LocalDate.

Related

f:setPropertyActionListener doesn't set the value however action is triggered

I need to set a boolean field whenever p:fieldset is toggled. I tried out following code but the field is never set by f:setPropertyActionListener although p:ajax listener is invoked on toggle. I tried out following code.
<p:fieldset legend="(Optional) Link.." toggleable="true">
<p:ajax event="toggle" listener="..">
<f:setPropertyActionListener target="#{viewScope.rendrUsrProjctsList}" value="#{true}"/>
</p:ajax>
</p:fieldset>
However when I tried modifying the code as below then field is successfully set:
<p:fieldset legend="(Optional) Link.." toggleable="true">
<p:ajax event="toggle" listener="#{view.viewMap.put('rendrUsrProjctsList', true)}" />
<p:ajax event="toggle" listener=".."/>
</p:ajax>
</p:fieldset>
I want to ask:
Why 1st way doesn't work ?
Is it bad attaching multiple p:ajax to
single parent as done in 2nd way ?
The <f:setPropertyActionListener> works as being an ActionListener implementation only on components implementing ActionSource interface, such as UICommand, i.e. <h:commandXxx>, <p:commandXxx>, etc. The <p:ajax> does not implement this interface and therefore the <f:setPropertyActionListener> is basically completely ignored.
As to your workaround, you could do so although I'd rather just use a concrete view scoped bean or wrap it in a composite with a backing component.

Update form from value change of Primefaces spinner

I am trying to update my form on the basis of changes of the spinner
<p:spinner id="spin1" min="1" max="#{editPhoto.max}" size="1"
value="#{editPhoto.page}" validator="#{editPhoto.validator()}"
valueChangeListener="#{editPhoto.refreshForm()}" />
<p:commandButton value="Insert" action="#{editPhoto.insertImage()}" />
<p:commandButton value="Delete" action="#{editPhoto.deleteImage()}" />
I've put break points in the value, setPage as well as in the validator and valueChangeListener and it hits them only when I press the commandButton. I've tried immediate="true", but that adds nothing. What I really want is to know when the value has been changed, but without having to hit the commandButton.
In a previous question BalusC suggested the use of
<f:event type="preRenderView" listener="#{nextpageBacking.onPreRenderView}" />
I suspect that I need something similar here, but what sort of event should I be looking for? Maybe not, so what do I need to do to get changes in the spinner without having to press on the commandButton? Thanks, Ilan
My bean is view-scoped. Perhaps the answer is to use another request scoped-bean and have the request scoped-bean operate on the view-scoped bean? I will try this if this looks like the correct direction.
You should use f:ajax or p:ajax.
The valueChangeListener will only fire when the whole form or the spinner is submitted.
<p:spinner id="spin1" min="1" max="#{editPhoto.max}" size="1"
value="#{editPhoto.page}" validator="#{editPhoto.validator()}">
<p:ajax listener="#{editPhoto.refreshForm()}"
update="#form" process="#this" />
</p:spinner>
The valueChangeListener attribute of the spinner is not the best place to fire your method. You should better put it in the listener attribute of p:ajax. The valueChangeListener should be used if you are interested in the old and the new value.

How to bind a Date with calendar control in primefaces using binding attribute?

I want to bind a date with a calendar control after a specific value is selected from an autocomplete. But the following exception occurs :
javax.servlet.ServletException: java.util.Date cannot be cast to javax.faces.component.UIComponent
<p:autoComplete value="#{rechargeCustomerBean.school.schoolName}" completeMethod="#{rechargeCustomerBean.completeSchool}" required="true" />
<p:calendar mode="popup"
navigator="true" pattern="dd-MM-yyyy" effect="fadeIn"
showButtonPanel="true"
binding="#{rechargeCustomerBean.school.expiryDate}" />
Are you sure you want to bind?
Use the value attribute instead.
Also, add <p:ajax to your calendar to update the calendar and you are ready to go.
like this
<p:autoComplete value="#{rechargeCustomerBean.school.schoolName}" completeMethod="#{rechargeCustomerBean.completeSchool}" required="true">
<p:ajax event="itemSelect" update="idOfCalendar" />
</p:autoComplete>
Change
binding="#{rechargeCustomerBean.school.expiryDate}"
into
value="#{rechargeCustomerBean.school.expiryDate}"
so it will look like this
<p:calendar value="#{rechargeCustomerBean.school.expiryDate}" id="idOfCalendar"..... />
use of binding attribute in <p:calender> might cause the problem...try chaging it with value=#{...}
also make sure your bean's "expiryDate" is of type Util.Date
hope this could resolve your problem..for detailed explanation see here

Validating a wrong date entry in rich faces

In one of our functionality we have some date fields for inline edit where we have enabled manual input. If in rich:calendar component, we manually enter improper date or junk data it will not even call the action method. As per our requirement we need to display an error message for date validation for these kind of fields. Is there any way to track that the date entered in the calendar field is improper with this component.
Code for the reference:
<rich:calendar id="actualOpeningDtCal" rendered="#{!empty aProgram.id}"
value="#{aProgram.actualOpeningDate}" placeholder="dd-mmm-yyyy"
inputSize="20" enableManualInput="true" datePattern="dd-MMM-yyyy"
buttonIcon="../content/images/calendar.png" showWeeksBar="false"
showFooter="false">
<a4j:support event="oninputblur" reRender="aList" ajaxSingle="false"
action="#{aController.inlineEdit}">
<f:setPropertyActionListener value="#{aProgram}"
target="#{aController.inLineEditaBean}" />
</a4j:support>
<a4j:support event="oncollapse" reRender="aList" ajaxSingle="false"
action="#{aController.inlineEdit}">
<f:setPropertyActionListener value="#{aProgram}"
target="#{aController.inLineEditaBean}" />
</a4j:support>
</rich:calendar>
If validation fails, then there are error messages. Perhaps you aren't showing them. Use <rich:messages> instead of <h:messages> to have them rendered on ajax response.
A bad practice, but might work, would be to use immediate="true" (bypasses validation) and then do the validation in the action method.

Form value not passed to Seam bean after a4j reRender

I'm making a webapp in Seam but ran into a problem I can't seem to fix.
I have a JSF form where the customer can select a reservation type through a combobox. Based on the selected value, other form components gets rendered.
For example: the customer selects Hours as reservation type, a panelGroup gets rendered where the customer can select a start- and an end hour. But if the customer would select 'part of the day' as reservation type, a selectOneMenu gets rendered where the customer can select a part of the day (morning, afternoon, evening)
The rerendering well but the values of the components with a rendered conditional won't get passed to the bean. They stay null values.
This is the code i'm talking about:
<s:div id="spot"
rendered="#{selectedProduct.productType.name eq 'Flex Spot'}">
<h:panelGrid columns="2">
<h:outputText value="Reservation Type" />
<h:selectOneMenu value="#{selectedPeriodPart}">
<s:selectItems
value="#{productManager.getAvailableDayPartsSpot()}"
var="daypart"
label="#{daypart.label}"></s:selectItems>
<s:convertEnum />
<a4j:support ajaxSingle="true"
event="onchange"
action="#"
reRender="spot">
</a4j:support>
</h:selectOneMenu>
<h:outputText id="date_spot" value="Date" />
<a4j:outputPanel id="calendar_spot" layout="block">
<rich:calendar value="#{reservation.reservationPeriod.startDate}"
locale="en" cellWidth="24px"
cellHeight="22px"
style="width:200px" />
</a4j:outputPanel>
<h:outputText rendered="#{selectedPeriodPart eq 'DAY_PART'}"
value="Daypart" />
<h:selectOneMenu value="#{selectedDaypart}"
rendered="#{selectedPeriodPart eq 'DAY_PART'}">
<f:selectItem id="si_morning" itemLabel="Morning (6:00 - 12:00)"
itemValue="morning" />
<f:selectItem id="si_afternoon"
itemLabel="Afternoon (12:00 - 18:00)" itemValue="afternoon" />
<f:selectItem id="si_evening" itemLabel="Evening (18:00 - 00:00)"
itemValue="evening" />
</h:selectOneMenu>
<h:outputText rendered="#{selectedPeriodPart eq 'HOURS'}"
value="Hours" />
<h:panelGroup id="hours_spot"
rendered="#{selectedPeriodPart eq 'HOURS'}">
<ui:include src="/includes/reservation/select_hours.xhtml" />
</h:panelGroup>
</h:panelGrid>
</s:div>
Note: The calendar value do get passed back to the bean but the value of this piece of code doesn't (it does if you remove the rendered conditional):
selectOneMenu value="#{selectedDaypart}" rendered="#{selectedPeriodPart eq 'DAY_PART'}"
You need to ensure that the conditionals responsible for the outcome of the rendered attribute are also the same in the subsequent request of the form submit. Because when a component isn't rendered, JSF won't apply the request values them.
In a nutshell, the property behind #{selectedPeriodPart} needs to be the same in the subsequent request. There are several solutions:
Put bean in session scope. Easiest solution, but bad for server memory and client experience (updates would be reflected in multiple tabs/windows in same session).
Pass it through using <h:inputHidden>. Not sure though how this fits in the Ajax/Richfaces picture. Better use <a4j:keepAlive> here.
Use a conversation scope. Seam offers facilities for this.
I fixed it -.- Nothing was wrong with the code I posted.
Because I wasn't able to solve this issue I continued on an other page in the same conversation. I noticed some more strange behaviour: outjection of a variable didn't work etc.
I figured the mistake was in some other part of the code which, after corrected, fixed the whole problem.
Thx for answering guys!

Resources