Recently I have update my application to JSF 2.1.7 and PrimeFaces 3.4.2. When the below dialog is used for adding a new group, I get an "Name size must be between 1 and 40" validation error, prior to saving the new group. It happens when I click the picker's add button. I understand that this message is shown because the validation failed. The validation error doesn't appear when I add immediate=true to p:commandButton. I don't know what triggered the validation.
<h:form id="formg" prependId="false">
<!-- messages -->
<p:growl id="msgsg" showDetail="true" />
<!-- data table -->
<ui:include src="/WEB-INF/flows/groupsTable.xhtml" />
<p:separator />
<!-- bottom tool bar -->
<ui:include src="/WEB-INF/flows/groupsToolBar.xhtml" />
<!-- preview, edit dialog -->
<ui:include src="/WEB-INF/flows/groupsDialog.xhtml" />
</h:form>
<p:dialog id="dialogg" header="#{groupsBean.dialogTitle}"
widgetVar="groupsDialog" dynamic="true" resizable="false" width="800"
height="600" showEffect="fade" hideEffect="fade" modal="true">
<p:ajax event="close" listener="#{groupsBean.refresh}"
immediate="true" update=":formg" global="false" process="#this" />
<p:tabView id="tabPicker">
<p:tab title="General">
<h:panelGrid id="displayg" columns="2">
<h:outputText value="#Group name*:" />
<p:inputText value="#{groupsBean.selectedGroup.name}" size="40"
readonly="#{!groupsBean.updatable}" maxlength="40" />
</h:panelGrid>
</p:tab>
<p:tab title="Members">
<ui:include src="/WEB-INF/custom/picker.xhtml">
... some params passed to picker
</ui:include>
</p:tab>
</p:tabView>
</p:dialog>
The picker is similar to <p:password> and it is made up from two p:dataTable components and 4 buttons between them. The buttons are grouped together with a h:panelGrid. The button attributes are similar. Here is button sample code:
<p:outputPanel autoUpdate="true">
<p:commandButton actionListener="#{eval.evaluateAsMethod(pickerAdd)}"
update="source, target, #{messages}" immediate="true"
disabled="#{pickerSourceDisabled}"
icon="ui-icon ui-icon-arrowthick-1-s" />
</p:outputPanel>
source, target are the ids of the two datatables. pickerAdd is passed as param with a value of groupsBean.picker.add. The tables contain FooDomain objects.
public class FooDomain implements Serializable {
...
#NotNull
#Size(min = 1, max = 40)
#Column(name = "NAME")
private String name;
...
}
The PrimeFaces <p:commandButton> processes by default the entire form (as in, process="#form"), so it would by default trigger all validations. Your validation error is coming from the #Size restriction on the property. If you would like to process only the button's own action, then you should add process="#this".
<p:commandButton ... process="#this" />
The immediate="true" can also be used to solve it, but it behaves under the covers somewhat different: the entire form is still processed, but the action is invoked in APPLY_REQUEST_VALUES phase instead of INVOKE_ACTION phase. And only the input components which also have immediate="true" set will also be processed and others will be skipped.
Related
I have a table with <a:commandLink> that opens <rich:modalPanel> with additional info on the selected item. It works using reRendering modalPanel's inner <a:outputPanel> on click on the commandLink. Now the issue that all my facelets become usual input items (i.e simple selects instead of comboboxes) after reRender. Is there any way to make the server add the ui info to the reRendered result?
UPD I see the following messages in log
10:55:30,483 INFO [facelet] Facelet[/account/registration.xhtml] was modified # 10:55:30 AM, flushing component applied # 10:54:36 AM
UPD2 The issue happens only with the components that replace usual select, like selectOneMenu or selectonelistbox.
Code examples:
<rich:modalPanel id="fieldPropertiesPanel" >
<f:facet name="header">
<h:outputText value="Customize Field" />
</f:facet>
<f:facet name="controls">
<h:outputLink value="#"
onclick="#{rich:component('fieldPropertiesPanel')}.hide(); return false;">
X
</h:outputLink>
</f:facet>
<rich:panel id="fieldPropertiesContent">
<s:decorate styleClass="itemType" template="/layout/edit.xhtml">
<h:selectOneMenu value="#{accountHome.currFieldType}">
<s:selectItems itemLabel="#{fieldType}" itemValue="#{fieldType}"
label="#{messages['ProjectFieldType_enum.'.concat(fieldType)]}"
value="#{accountHome.projectFieldTypes}" var="fieldType" />
</h:selectOneMenu>
</s:decorate>
</rich:panel>
</rich:modalPanel>
and the calling commandLink
<a:commandLink value="Edit" oncomplete="Richfaces.showModalPanel('fieldPropertiesPanel');"
reRender="fieldPropertiesContent" />
I have a JSF 2.0 application using Primefaces 3.0M4 component library. I have the following input:
<p:inputText id="input" value="#{bean.value}" required="true">
<p:ajax event="blur" update="msg" />
</p:inputText>
<p:message id="msg" for="input" />
what I would like to do is that in case validation fails (the value is empty), focus returns to the component, forcing the user to enter a value. is this possible?
Also I would like that when user clicks the submit button; if validation fails there, the first component that did not pass the validation is focused.
Thanks,
Damian
It is possible, client-side, by using the required and requiredMessage attributes. The user can't submit the form and a error message is shown:
<h:outputLabel for="firstname" value="Firstname: *" />
<p:inputText id="firstname"
value="#{personBean.firstname}"
required="true" requiredMessage="You have to enter your name" label="Firstname">
<f:validateLength minimum="2" />
</p:inputText>
<p:message for="firstname" />
You could use primefaces message if you don't use requiredMessage attribute, because it will show you two warning messages and it's a bit strange...
For the focus it depends...what if you have two inputTexts? Do you want to show the focus only for the first one?
You can see a demo here: http://www.primefaces.org/showcase-labs/ui/pprAjaxStatusScript.jsf
For <f:selectItem> there is no rendered attribute. How can I hide a particular <f:selectItem> under <h:selectOneRadio>?
<h:selectOneRadio id="radio1" styleClass="selectOneRadio" value="#{}" rendered="#{}">
<f:selectItem itemValue="ALL" itemLabel="#{ONE}" />
<f:selectItem itemValue="PRIVATE" itemLabel="#{TWO}" />
<f:selectItem itemValue="GROUP" itemLabel="#{THREE}" />
</h:selectOneRadio>
In above code I want to hide the second item.
The <f:selectItem> is a tag handler (which evaluated during view build time), not a JSF component (which is evaluated during view render time). You can only show/hide it with another tag handler, such as JSTL <c:if>.
<h:selectOneRadio value="#{bean.selectedItem}">
<f:selectItem itemValue="ALL" itemLabel="#{ONE}" />
<c:if test="#{!bean.showPrivate}">
<f:selectItem itemValue="PRIVATE" itemLabel="#{TWO}" />
</c:if>
<f:selectItem itemValue="GROUP" itemLabel="#{THREE}" />
</h:selectOneRadio>
Only when #{bean} is been prepared during view render time by an iterating JSF component such as <h:dataTable> or <ui:repeat> then the above won't work and you really have to do it in the backing bean code instead.
You can use f:selectItems .
For example:
<h:selectOneRadio id="radio1" styleClass="selectOneRadio" rendered="true" value="controller.value">
<f:selectItems value="#{controller.items}" />
</h:selectOneRadio >
This is class controller:
public clss Controller(){
private List<SelectItem> items = new ArrayList<SelectItem>();
public Collection<SelectItem> getItems(){
if (items.isEmpty()){
createItems();
}
return this.items;
}
public private createItems(){
if (condition){ //Here you can hidden the selectItem
this.items.add(new SelectItem(value,label));
}
}
}
you can try to surround it in
<h:panelGrid rendered="">
h:selectOneRadio
</h:panelGrid >
EDITED:
or use
<h:panelGroup>
Edit
its not good idea but i think you can do it by code redundancy as follow
<h:panelGroup rendered="#{}">
<h:selectOneRadio id="radio1" styleClass="selectOneRadio" rendered="true">
<f:selectItem itemValue="ALL" itemLabel="one" />
<f:selectItem itemValue="PRIVATE" itemLabel="two" />
<f:selectItem itemValue="GROUP" itemLabel="THREE" />
</h:selectOneRadio>
</h:panelGroup>
<h:panelGroup rendered="#{!}">
<h:selectOneRadio id="radio11" styleClass="selectOneRadio" rendered="true">
<f:selectItem itemValue="ALL" itemLabel="one" />
<f:selectItem itemValue="PRIVATE" itemLabel="two" />
</h:selectOneRadio>
</h:panelGroup>
I am not able to understand the markup/source, but guessing from the heading, I will suggest
$("a.selectOneRadio f.selectItem").hide()
should do the job assuming
1) selectOneRadio is the class name of the a tag.
2) selectItem is the class name of the f tag.
3) f is not a tag in HTML. So if `f` is also a class name, you would have to use `.f .selectItem`
If you can please provide some details in the question.
There is also a disabled property on f:selectItem elements, if that fulfills your needs. Otherwise you will have to add them manually as Michel Foucault suggested.
This question is mainly directed at the PrimeFaces dev team but maybe someone else knows a workaround. I can't upload screenshots on the PrimeFaces support forums but I can link to my question here.
Reported as a defect in PrimeFaces issue tracker. Add a star to cast your vote for the PrimeFaces development team to fix this: link to defect in their issue tracker
Discussed here in PrimeFaces support forum.
Still exists in PrimeFaces 3.0-M3-SNAPSHOT
PROBLEM:
I'm using the PrimeFaces 3.0 <p:calendar> control to allow the user to view and edit Date objects that contain both date and time. There appears to be some defect in the JavaScript control that causes it to add some strange offset to the date somewhere in the vicinity of +6 years.
I have setup some code to demonstrate the problem.
In the first <p:calendar> I use a managed bean Date that is initially null. The control is ok with that. It will open and set the initial value to the current date with hour/minute/second zeroed. I can use the sliders to set the hours, minutes and seconds normally.
In the second <p:calendar> I use a managed bean Date that is initially set to new Date(). This will create a new Date object set to the current server time. The control is not ok with that. Although the date/time displayed in the <p:calendar> box looks correct initially, it will be modified to some bizarre value in the future when the JavaScript picker control is opened. On closing the picker control the date on the managed bean is set to the bizarre value.
Another problem that may or may not be related is when I try to use a custom format for the date:
ddHHmm'Z'MMMyy
This format is used by my customer in their domain and I need to support it somehow. The <p:calendar> JavaScript picker will not even open when I try to click on the box. Something about the pattern (which works just fine in Java SimpleDateFormat) breaks it. The PrimeFaces documentation is silent on this.
QUESTION: Does anyone have any workaround for these <p:calendar> issues?
UPDATE - source code:
The composite component that wraps the <p:calendar>:
<?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:p="http://primefaces.prime.com.tr/ui"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface
displayName="calendar"
shortDescription="Wrapper for a PrimeFaces p:calendar">
<composite:attribute
name="dateValue"
displayName="dateValue"
type="java.util.Date"
required="true"
shortDescription="EL expression that evaluates to a java.util.Date on a backing bean" />
<composite:attribute
name="pattern"
displayName="pattern"
type="java.lang.String"
default="dd/MM/yyyy HH:mm:ss"
shortDescription="Pattern used to format the underlying Date value. See SimpleDatePattern class documentation for pattern syntax. NOTE: p:calendar does not appear to support some complex patterns." />
<composite:attribute
name="ajaxRenderTargets"
displayName="ajaxRenderTargets"
type="java.lang.String"
default="#none"
shortDescription="Space-separated list of element ids that need to be rendered by Ajax when the calendar value changes. See f:ajax render attribute documentation." />
<composite:attribute
name="tooltip"
displayName="tooltip"
type="java.lang.String"
default=""
shortDescription="String to be used as the tooltip for this component" />
<composite:attribute
name="label"
displayName="label"
type="java.lang.String"
default=""
shortDescription="Label for this component. May be used in FacesMessages." />
<composite:attribute
name="required"
displayName="required"
type="java.lang.Boolean"
default="false" />
</composite:interface>
<composite:implementation>
<p:calendar
id="pCalendarInsideCC"
value="#{cc.attrs.dateValue}"
pattern="#{cc.attrs.pattern}"
readOnlyInputText="true"
showButtonPanel="false"
popupIconOnly="false"
showOn="focus"
mode="popup"
navigator="true"
pages="1"
showOtherMonths="true"
selectOtherMonths="false"
alt="#{cc.attrs.tooltip}"
title="#{cc.attrs.tooltip}"
required="#{cc.attrs.required}"
label="#{cc.attrs.label}">
<p:ajax
event="valueChange"
update="#{cc.attrs.ajaxRenderTargets}" />
<p:ajax
event="change"
update="#{cc.attrs.ajaxRenderTargets}" />
</p:calendar>
</composite:implementation>
</html>
The page containing the composite component references:
<ui:composition template="/templates/primefaces/masterLayout.xhtml">
<ui:param name="title" value="#{bundle.primeFacesCalendarCC_description}" />
<ui:define name="content">
<h:form id="contentForm">
<h:panelGrid columns="3">
<h:outputText
value="Initially empty Date reference on managed bean" />
<sandbox:primeFacesCalendar
id="calendarCC1"
dateValue="#{primeFacesTestBean.userSubmittedDateTime}"
ajaxRenderTargets="messagesCalendar1 :ajaxRenderTargetsInTemplate"
required="true" />
<p:messages
id="messagesCalendar1"
showSummary="false"
showDetail="true" />
<h:outputText
value="A 'new Date()' reference on managed bean" />
<sandbox:primeFacesCalendar
id="calendarCC2"
dateValue="#{primeFacesTestBean.newDateInstance}"
ajaxRenderTargets="messagesCalendar2 :ajaxRenderTargetsInTemplate"
required="true" />
<p:messages
id="messagesCalendar2"
showSummary="false"
showDetail="true" />
<h:outputText
value="Initially empty Date using ddHHmm'Z'MMMyy pattern" />
<sandbox:primeFacesCalendar
id="calendarCC3"
dateValue="#{primeFacesTestBean.userSubmittedDateTime}"
ajaxRenderTargets="messagesCalendar2 :ajaxRenderTargetsInTemplate"
pattern="ddHHmm'Z'MMMyy"
required="true" />
<p:messages
id="messagesCalendar3"
showSummary="false"
showDetail="true" />
</h:panelGrid>
</h:form>
</ui:define>
</ui:composition>
<ui:composition template="/templates/primefaces/masterLayout.xhtml">
<ui:param name="title" value="#{bundle.primeFacesCalendarCC_description}" />
<ui:define name="content">
<h:form id="contentForm">
<h:panelGrid columns="3">
<h:outputText
value="Initially empty Date reference on managed bean" />
<sandbox:primeFacesCalendar
id="calendarCC1"
dateValue="#{primeFacesTestBean.userSubmittedDateTime}"
ajaxRenderTargets="messagesCalendar1 :ajaxRenderTargetsInTemplate"
required="true" />
<p:messages
id="messagesCalendar1"
showSummary="false"
showDetail="true" />
<h:outputText
value="A 'new Date()' reference on managed bean" />
<sandbox:primeFacesCalendar
id="calendarCC2"
dateValue="#{primeFacesTestBean.newDateInstance}"
ajaxRenderTargets="messagesCalendar2 :ajaxRenderTargetsInTemplate"
required="true" />
<p:messages
id="messagesCalendar2"
showSummary="false"
showDetail="true" />
<h:outputText
value="Initially empty Date using ddHHmm'Z'MMMyy pattern" />
<sandbox:primeFacesCalendar
id="calendarCC3"
dateValue="#{primeFacesTestBean.userSubmittedDateTime}"
ajaxRenderTargets="messagesCalendar2 :ajaxRenderTargetsInTemplate"
pattern="ddHHmm'Z'MMMyy"
required="true" />
<p:messages
id="messagesCalendar3"
showSummary="false"
showDetail="true" />
</h:panelGrid>
</h:form>
</ui:define>
</ui:composition>
The managed bean:
#ManagedBean(name="primeFacesTestBean")
#SessionScoped
public class PrimeFacesTestBean implements Serializable {
private static final long serialVersionUID = 1L;
private Date userSubmittedDateTime = null;
private Date newDateInstance = new Date();
public void setUserSubmittedDateTime(Date userSubmittedDateTime) {
this.userSubmittedDateTime = userSubmittedDateTime;
}
public Date getUserSubmittedDateTime() {
return userSubmittedDateTime;
}
public void setNewDateInstance(Date newDateInstance) {
this.newDateInstance = newDateInstance;
}
public Date getNewDateInstance() {
return newDateInstance;
}
public void calendarValueChangeHandler(AjaxBehaviorEvent event) {
//System.out.println("calendar value has been changed (Ajaxified)");
}
}
Fixed as of August 18th in 3.0-M3-SNAPSHOT:
http://code.google.com/p/primefaces/issues/detail?id=2215
Confirmed that it works correctly in my webapp using the 3.0-M3-SNAPSHOT of August 23rd.
NOTE: The custom format issue was not covered in this defect. I'm not sure if that is fixed or still a problem.
In my application, I have a tree with various object types (sources, tables, etc).
I'd like to enable a context menu for the different types of object (add, delete, edit etc).
How can I use context menu on tree nodes in Primefaces ?
Never did it in practice (I am still on Primefaces 2.x), but from theory the facelet code should look something like this:
<h:form>
<p:tree value="#{myBean.tree}" var="node" id="tree"
selectionMode="single" selection="#{myBean.selectedNode}">
<p:treeNode>
<h:outputText value="#{node}" />
</p:treeNode>
</p:tree>
<p:contextMenu for="tree" id="menu">
<p:menuitem value="Add" actionListener="#{myBean.add}" />
...
</p:contextMenu>
</h:form>
Usage of p:contextMenu and p:tree is shown in Primefaces showcase.