In register.xhtml page, I have 2 inputText components for password and confirm password as following:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.prime.com.tr/ui"
xmlns:f="http://java.sun.com/jsf/core">
<h:form>
<h:outputText style="font-weight: bold" value="Password: " />
<p:password feedback="true" minLength="9"
binding="#{mrBean.passwordComponent}"
id="password" value="#{mrBean.password}"/>
<p:message for="password" id="passwordMsg" />
<h:outputText style="font-weight: bold" value="Confirm password: " />
<p:password feedback="false" minLength="9"
id="confirmPassword" value="#{mrBean.confirmPassword}"
validator="#{mrBean.validateConfirmPassword}>
<f:attribute name="oriPassword" value="#{mrBean.passwordComponent.submittedValue}"/>
<p:ajax process="password confirmPassword" update="confirmPasswordMsg" />
</p:password>
<p:message for="confirmPassword" id="confirmPasswordMsg" />
</h:form>
</html>
And this is my mrBean:
#ManagedBean
#RequestScoped
public class MrBean {
private String password;
private String confirmPassword;
private UIInput passwordComponent;
public void validateConfirmPassword(FacesContext context, UIComponent toValidate,
Object value) throws ValidatorException {
String passwordStr = (String) toValidate.getAttributes().get("oriPassword");
String confirmPasswordStr = (String) value;
if (!confirmPasswordStr.equals(passwordStr)) {
FacesMessage message = new FacesMessage("The 2 passwords do not match.");
throw new ValidatorException(message);
}
}
}
In another page, I also have a similar bean with similar validate function for email & confirmEmail and it works perfectly. However, I have no idea why it couldn't work here. The passwordStr is always null even though I have already entered the password.
I'd be very grateful if someone could show me what I have done wrong here.
Best regards,
James Tran
JSF components are processed in the order they appear in the component tree. During validations phase, for each component the submitted value will be retrieved by getSubmittedValue(), converted and validated. If no exceptions occurred during conversion and validation, then the submitted value will be set to null and the converted and validated value will be set as local value by setValue().
You're trying to reference the submitted value of the component which has already been processed at that point. The submitted value will only be non-null when conversion/validation failed for that value. You need to reference its local value instead.
<f:attribute name="oriPassword" value="#{mrBean.passwordComponent.value}"/>
See also:
How validate two password fields by ajax? (this example does the other way round, so that you don't need an additional property for confirm password)
Related
edit: Based on Jasper's comment, the selection feature requires p:dataTable to be in a form, so my question is moot.
I have a DataTable outside of a form. When I submit the form (non-ajax), the field referenced by the selection attribute is set to null in my view. This happens for PrimeFaces 10.0.1 and higher. In 10.0.0 and 8.x, the field is not touched.
The field in the example is DtView.selectedEntry.
xhtml:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.org/ui"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>PrimeFaces Test</title>
</h:head>
<h:body>
<p:dataTable id="data-table" var="entry"
value="#{dtView.entries}"
rowKey="#{entry.id}"
selection="#{dtView.selectedEntry}"
selectionMode="single">
<p:column headerText="Entry">
<h:outputText value="#{entry}" />
</p:column>
</p:dataTable>
<h:form id="frmTest">
<div>
<p:outputLabel for="#next" value="Selected: "/>
<h:outputText id="selected-entry" value="#{dtView.selectedEntry}" />
</div>
<div>
<p:commandButton value="save input"
ajax="false"
imediate="true"
update="#form :data-table"
action="#{dtView.submit()}" />
</div>
</h:form>
</h:body>
</html>
View:
#Data
#Named
#ViewScoped
public class DtView implements Serializable {
private List<Product> entries;
private Product selectedEntry;
#PostConstruct
void setup() {
entries = List.of(
new Product(1, "entry 1"),
new Product(2, "entry 2"),
new Product(3, "entry 3")
);
selectedEntry = entries.get(0);
}
public String submit() {
System.out.println("Selected entry: " + selectedEntry);
return null;
}
}
Console (PrimeFaces 11.0.0 and then 10.0.0):
Selected entry: null
Selected entry: Product(id=1, name=entry 1)
To avoid the 'null' I can put p:dataTable inside a form, so it won't get processed during the apply request value phase or use ajax on the command button. I am not sure why the dataTable is outside a form in my real application to begin with.
I expected a value outside of a form not to be set in the view, but dataTable does not seem to follow this. Is the new PF behaviour more logical and my understanding is wrong?
The reason for this change seems to be located in SelectionFeature.
PF 8: just calls table.setSelection(null);:
https://github.com/primefaces/primefaces/blob/cd4fbdf1d9d4ae054da19b9a84001d0c34d142eb/src/main/java/org/primefaces/component/datatable/feature/SelectionFeature.java#L78
PF 10.0.0: decodeSingleSelection() does not call setSelection() because !rowKeys.isEmpty() evaluates to false (empty check disappears in 10.0.1):
https://github.com/primefaces/primefaces/blob/10.0.0/src/main/java/org/primefaces/component/datatable/feature/SelectionFeature.java#L84
11.0.0: decodeSingleSelection() eventually calls setSelection() to set the value in the view to null:
https://github.com/primefaces/primefaces/blob/11.0.0/primefaces/src/main/java/org/primefaces/component/datatable/feature/SelectionFeature.java#L87
I am trying to make a form with options to add rows. However, after I type in some input and click the add button again, the input I enter disappears. I'm not sure what is wrong with my code. In addition, when I click the add button, the page refreshes. Is there way to stop this page refresh?
Person.java
public class Person{
private List<String> guys = new ArrayList<String>();
public List<String> getGuys() {
return guys;
}
public void setGuys(List<String> guys) {
this.guys = guys;
public void addNewItem(){
guys.add("");
}
}
form.xhtml
<h:form>
<h:panelGrid columns="2">
<h:outputText value="Guys: " />
<h:dataTable value="#{person.guys}" var="men">
<h:column>
<p:inputText value="#{men}" />
</h:column>
</h:dataTable>
<h:commandButton name="add" value="Add" action="#{person.addNewItem}" />
</h:panelGrid>
<br />
<h:commandButton name="submit" type="submit" value="Submit"></h:commandButton>
</h:form>
Provided that the bean is placed in the right scope for the functional requirement, the view scope, the only major mistake left is that you're expecting that the String class has some magic setter method.
It hasn't. The String class is immutable. The following will never work on a String:
<p:inputText value="#{men}" />
You have 2 options:
Create a real model class. You can find complete examples in the following answers:
How to dynamically add JSF components
Recommended JSF 2.0 CRUD frameworks
Set the value by row index instead:
<h:dataTable binding="#{table}" value="#{person.guys}">
<h:column>
<p:inputText value="#{person.guys[table.rowIndex]}" />
</h:column>
</h:dataTable>
(note: no additional bean property necessary for the table! the code is as-is)
This does basically a person.getGuys().add(table.getRowIndex(), submittedValue). I.e. the setter is invoked on the List itself, which works perfectly fine. See also the following related answers concerning ui:repeat:
Using <ui:repeat><h:inputText> on a List<String> doesn't update model values
How map multiple inputText to an array property?
You never update your list, you are just adding empty items. You should do something like this:
Person.java (viewscoped)
public class Person implements Serializable {
private List<String> guys = new ArrayList<String>();
private HtmlDataTable dtGuys;
public void addNewItem() {
guys.add("");
}
public void addToList(ValueChangeEvent e) {
guys.set(dtGuys.getRowIndex(), e.getNewValue().toString());
}
public String save() {
System.out.println("saving...");
for (String item : guys) {
System.out.println("item= " + item);
}
return null;
}
//gettes and setters
}
form.xhtml
<h:form id="frmPrincipal">
<h:panelGrid columns="2">
<h:outputText value="Guys: " />
<h:dataTable value="#{person.guys}" var="men" binding="#{person.dtGuys}" >
<h:column>
<p:inputText value="#{men}" valueChangeListener="#{person.addToList}" />
</h:column>
</h:dataTable>
<h:commandButton name="add" value="Add" action="#{person.addNewItem}" />
</h:panelGrid>
<br />
<h:commandButton id="submit" name="submit" value="Submit" action="#{person.save}"/>
</h:form>
Using jsf 2.0.10 and primefaces 3.5
Its because you don't have an scope for that bean, so its request scoped, so when you call the action the bean is created again, you can fix this using a sessionScope or conversationScope
I'm trying to get some code working in an XHTML/JSF/Spring application through which I send an ID to a bean function and expect a string in return. I haven't found an understandable tutorial on this nor any answered question here on SO.
XHTML:
<h:form>
<h:inputText id="inputId" value="#{npBean.idString}"/>
<a4j:commandButton value="get def" render="out">
<f:param value="#{npBean.idString}" name="id" />
<f:setPropertyActionListener target="#{npBean.definition}"/>
</a4j:commandButton>
<a4j:outputPanel id="out">
<h:outputText id="outputId" value="#{npBean.def}"
rendered="#{not empty npBean.def}"/>
</a4j:outputPanel>
</h:form>
Java:
public String getDefinition(int id)
{
def = this.getXService().getXData(id).getDefinition();
return def;
}
All values shown have their getters and setters in the bean.
What we basically do:
Map the value of the <h:inputText> component to a property (with getter/setter) in the managed-bean (which is called myBean)
By using the reRender attribute of the <a4j:commandButton> component, we point which component on the page to be re-rendered (refreshed) when the button is clicked.
When clicking on the button, the invokeService() method from the managedBean is executed and it updates the other property of the managedBean.
In the <h:panelGroup> below, we have several <h:outputText> components and with the rendered attribute we specify when a component has to be displayed on the page.
Exploring the managed-bean, the only thing that is required, are the accessors for the property, which holds the result from the service invoke.
Here's the *.xhtml sample:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<a4j:form>
<h:panelGrid columns="3">
<h:outputText value="String value:" />
<h:inputText value="#{myBean.value}" />
<a4j:commandButton value="Click" reRender="out">
<a4j:actionListener listener="#{myBean.invokeService}" />
</a4j:comandButton>
</h:panelGrid>
</a4j:form>
<rich:spacer height="7"/>
<br />
<h:panelGroup id="out">
<h:outputText value="Service returned: " rendered="#{not empty myBean.result}" />
<h:outputText value="#{myBean.result}" />
</h:panelGroup>
</ui:composition>
Managed-bean:
#ManagedBean(name = "myBean")
#SessionScoped //for example
public class MyBean {
private String value;
private String result;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getResult() {
return result;
}
public void invokeService(ActionEvent actionEvent) {
this.result = "Hello, " + value + "!";
}
}
As #Luiggi mentioned, the accessor methods MUST meet the following conventions (if we assume you have a private <some-type> property; in the managed-bean.)
public <some-type> getProperty {
return property;
}
public void setProperty(<some-type> property) {
this.property = property:
}
In order to learn how the RichFaces components work, combined with good code examples, I suggest you open this address and play around with the components.
i am using this way in custom validation i am little bit confused if this way is correct or not if i assumed that i have this form:
<h:form id="myForm>
<h:outputText value="user name" />
<h:inputText value="#userBean.userName" id="userName" />
<h:outputText value="Password" />
<h:inputText value="#userBean.Password" id="passwd" />
</h:form>
and i have its Managed Bean :
#ManagedBean(name="userBean")
#SessionScoped
public class UserBeanData{
private String userName;
private String password;
// with setters and getters........
//
}
and the custom validator to validate the Managed Bean field and the Implmentation like :
#Override
public validate(FacesContext context, UIComponent component, Object value) throws ValidatorException{
Map<String, String> params = context.getExternalContext().getRequestParametersMap();
String username = params.get("myForm:username");
String pass = params.get("myForm:passwd");
// validate : if fields are not null check if the user exists if the result is empty , throws a validation Message Error
}
My Question is : Retrieving the Managed bean values like this is true or not ????
You're basically looking for the solution in the wrong direction. Validation is only applicable on the individual submitted values, e.g. minimum/maximum length, non-empty/null, regex pattern, etcetera. But you want to invoke a business action based on all submitted values: logging-in an user. This is not exactly input validation.
Just add required="true" to the both input components and perform the job in the action method.
E.g.
<h:form id="myForm>
<h:outputText value="user name" />
<h:inputText value="#{userBean.userName}" id="userName" />
<h:message for="userName" />
<h:outputText value="Password" />
<h:inputSecret value="#{userBean.password}" id="passwd" />
<h:message for="passwd" />
<h:commandButton value="Login" action="#{userBean.login}" />
<h:messages globalOnly="true" />
</h:form>
with
#ManagedBean
#RequestScoped
public class UserBean {
private String userName;
private String password;
#EJB
private UserService service;
public String login() {
User user = service.find(userName, password);
if (user != null) {
FacesContext.getCurrentInstance().getExternalContext().getSessionMap("user", user);
return "home?faces-redirect=true";
} else {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Unknown login"));
return null;
}
}
// ...
}
Pay attention to the validate method's firm. It has an UIComponent parameter that is the component validated by the method. This UIComponent has both the current value (getValue()) and the value that the user submitted (getSubmittedValue()).
You might have to cast that UIComponent to the particular type of component you're validating (int this case, it's an UIInput).
Now, if you're going to validate both username and password prior to a log in, there are several ways to do it. In your case, validating the username field with the password field as an added parameter should suffice. You can achieve that by doing this:
<h:outputText value="user name" />
<h:inputText value="#userBean.userName" id="userName" validator="#{yourBean.validateLogin}">
<f:attribute name="pass" value="#{passwordField}" />
</h:inputText>
<h:outputText value="Password" />
<h:inputText value="#userBean.Password" id="passwd" binding="#{passwordField}"/>
Note that the binding in the password <h:inputText/> is related to the value of the pass of the <f:attribute/> tag nested in your username <h:inputText/>. With this setup, you can perform your validation like this:
public void validateLogin(FacesContext context, UIComponent component, Object value) throws ValidatorException {
//I suppose it's a typo, but your validate method lacks the return type.
String username = (String) value;
UIInput passwordInput = component.getAttributes().containsKey("pass") ?
(UIInput) component.getAttributes().get("pass") : null;
if(passwordInput != null) {
//Just to be sure the input was added as a parameter successfuly
String submittedPassword = passwordInput.getSubmittedValue();
//Now, do your validations based on the strings "username"
//and "password".
}
}
Since all of this is being done in the validation phase, the values aren't set in your managed bean yet, that's why you have to play around a little with the submitted values.
Migrating from WAS6.1+JSF1.1+richfaces.3.1.5 to WAS7+JSF1.2+facelets1.1.14+richfaces3.3.3.
Error/Status messages are not rendering using h:messages, even though on debugging the facescontext.getMessages() contains the messages.
On submitting a form, I am validating an input. If the validation fails I am adding an error msg to the facescontext. It can be for multiple inputs. Each error msg is added to the facescontext
FacesMessage message = new FacesMessage();
message.setDetail(msg);
message.setSummary(msg);
message.setSeverity(FacesMessage.SEVERITY_ERROR);
getFacesContext().addMessage(componentID, message);
and on the xhtml I am displaying it using h:messages
I was using jsp in WAS6.1 and JSF1.1 and this used to work fine
Thanks
Adding more details
My xhtml
<ui:composition template="/template.xhtml">
<ui:define name="content">
<div id="content-nosidebar">
<h:form id="uploadDoc1" >
<h:messages/>
<h:panelGrid id="panelGridContact" headerClass="standardPageHeader" width="100%" cellpadding="5">
<f:facet name="header">
<h:panelGroup>
<h:outputText value="Upload Contact Info" />
<hr/>
</h:panelGroup>
</f:facet>
<h:panelGroup id="msgId">
<xyz:errorMessages />
<xyz:statusMessages />
</h:panelGroup>
<h:panelGrid style="text-align: center;font-weight: bold;">
<h:outputText value="Click on Browse button to identify CSV file with contact information for upload."/>
<h:outputText value="File size limit is 10MB."/>
<h:panelGroup>
<rich:fileUpload id="fileuploader" fileUploadListener="#{uploadContactCntrl.onSubmit}"
acceptedTypes="csv" allowFlash="true" listHeight="50" addControlLabel="Select File" uploadControlLabel="Submit" clearControlLabel="clear"/>
</h:panelGroup>
<h:outputText value=" "/>
</h:panelGrid>
</h:panelGrid>
</h:form>
</div>
</ui:define>
</ui:composition>
errorMessages and statusMessages are common tags to display error(validation error) and status((like Update complete) messages
In the the backingbean on submit if an error is encountered (like "File not found" or "Database is down" I call a common method with the error/status message from the resource file.
WebUtils.addCustomErrorMessage("global.error.ContactInfo-DuplicateRecords-UserID", new String[]{userid,Integer.toString(j+1)}, Constants.RESOURCE_BUNDLE_NAME);
or
WebUtils.addCustomStatusMessage("global.error.ContactInfo-successMessage", new String[]{Integer.toString(noOfRowsInserted)}, Constants.RESOURCE_BUNDLE_NAME);
public static void addCustomErrorMessage(String msg, String componentID) {
FacesMessage message = new FacesMessage();
message.setDetail(msg);
message.setSummary(msg);
message.setSeverity(FacesMessage.SEVERITY_ERROR);
getFacesContext().addMessage(componentID, message);
}
public static void addCustomStatusMessage(String msg, String componentID) {
if (errorCodeParameters != null && errorCodeParameters.length > 0)
msg = MessageFormat.format(msg, (Object[])errorCodeParameters);
FacesMessage message = new FacesMessage();
message.setDetail(msg);
message.setSummary(msg);
message.setSeverity(FacesMessage.SEVERITY_INFO);
getFacesContext().addMessage(componentID, message);
}
We also use the same tags to display an error message when an error is encountered on an input field. For e.g. a Firstname field has invalid characters.
As mentioned earlier, this was working fine before we migrated to JSF1.2
Your answer need to have xhtml code too, any way i'm giving u sample for using validation in JSF 1.2...
The xhtml code should be like..
<h:inputText id="txt_project_name"
value="#{FIS_Project_Master.txt_project_name_value}"
validator="#{FIS_Project_Master.txt_project_name_validator}"/>
<h:message id="msg_txt_project_name" for="txt_project_name" />
The java code should be like...
public void txt_project_name_validator(FacesContext context, UIComponent component, Object value) {
if (bmwpProjectMstFacade.ispmProjName_exists(value.toString().toUpperCase().trim())) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_WARN, "Warning", "Project Name Already Exist");
throw new ValidatorException(message);
}
}