JSF2 h:selectOneMenu shows old value when Validation Failed
Asked Answered
A

2

6

I have a form with few input fields & a select one menu. All fields are required="true", firstName, lastName, emailAddress, password, country.

Test Case # 1: 1) Enter values in all input fields, leave firstName field without entering any value,
Select a country (eg: United States) and submit the form, we can see error message for firstName field required.

2) Keep the form as it is, with leaving firstName field without entering any value, then select country to "select one", and submit the form. we can see error message for firstName & country fields, But where as in dropdown it did not show "Select One", it shows United States (the previous selection).

I have the same problem with input fields, but i solved with a converter. Is there a way to solve this one. I went with few posts in stackoverflow, came to know that it is a bug in mojarra.

Here is my code...

userRegistration.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core" >      
 <h:body>
    <h:form id="registrationForm">     
    <h:messages layout="table" infoClass="infoMsgs" errorClass="errMsgs"/>

    <table>
        <tr>
            <td>First Name:</td>
            <td>
                <h:inputText size="40" maxlength="100" 
                             required="true" 
                             styleClass="#{component.valid ? '' : 'text_error'}"
                             value="#{registrationAction.firstName}" />
            </td>
        </tr>
        <tr>
            <td>Last Name:</td>
            <td>
                <h:inputText size="40" maxlength="100" 
                             required="true" 
                             styleClass="#{component.valid ? '' : 'text_error'}"
                             value="#{registrationAction.lastName}" />
            </td>
        </tr>
        <tr>
            <td>Email Address:</td>
            <td>
                <h:inputText size="40" maxlength="100" 
                             required="true" 
                             styleClass="#{component.valid ? '' : 'text_error'}"
                             value="#{registrationAction.emailAddress}" />
            </td>
        </tr>
        <tr>
            <td>Password:</td>
            <td>
                <h:inputSecret size="20" maxlength="15" 
                             required="true" 
                             styleClass="#{component.valid ? '' : 'text_error'}"
                             value="#{registrationAction.password}" />
            </td>
        </tr>
        <tr>
            <td>Country:</td>
            <td>
                <h:selectOneMenu id="yourCountry" name="yourCountry"    
                                 value="#{shortRegistrationAction.shortRegistrationForm.selectedCountry}"
                                 required="true" 
                                 styleClass="#{component.valid ? '' : 'text_error'}">
                    <f:selectItem itemValue="#{null}" itemLabel="-Select One-" />
                    <f:selectItems value="#{registrationAction.countryList}" />
                </h:selectOneMenu>
            </td>
        </tr>
        <tr>
            <td>&#160;</td>
            <td>
                <h:commandButton name="RegisterButton" id="RegisterButton" 
                                 styleClass="submitbutton"
                                 value="Register"
                                 action="#{registrationAction.registerUser}" />
            </td>
    </table>
    </h:form>
</h:body>
</html>

RegistrationAction.java

package com.ebiz.web.bean;

import java.io.Serializable;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import com.ebiz.service.ICountryService;
import com.ebiz.service.IUserService;
import com.ebiz.vo.UserVO;
import org.apache.log4j.Logger;

@ManagedBean(name = "registrationAction")
@ViewScoped
public class RegistrationAction implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final Logger log = Logger.getLogger(RegistrationAction.class);

    @ManagedProperty("#{countryService}")
    private ICountryService countryService;

    @ManagedProperty("#{userService}")
    private IUserService userService;

    private String firstName;
    private String lastName;
    private String emailAddress;
    private String password;
    private String selectedCountry;
    private List<String> countryList;

    @PostConstruct
    public void init(){
        countryList = countryService.getCountryList();
    }

    public void registerUser() {

        UserVO userVO = new UserVO();
        userVO.setFirstName(firstName);
        userVO.setLastName(lastName);
        userVO.setEmailAddress(emailAddress);
        userVO.setPassword(password);
        userVO.setCountry(selectedCountry);

        userService.registerUser(userVO);

    }
}

InputTextTrimmer.java

package com.ebiz.web.converter;

import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;

@FacesConverter(forClass=String.class)
public class InputTextTrimmer implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        //return value != null ? value.trim() : null;
         if (value == null || value.trim().isEmpty()) {
             if (component instanceof EditableValueHolder) {
                 ((EditableValueHolder) component).setSubmittedValue(null);
                 ((EditableValueHolder) component).resetValue();
             }
             return null;
         }
         return value;
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        return (value == null) ? null : value.toString();
    }

}
Amino answered 21/11, 2012 at 1:28 Comment(0)
U
0

Take a look at the following BalusC blog post Reset non-processed input components on ajax update

You can add OmniFaces to your project and make use of its ResetInputAjaxActionListener

So you'll have to update your code into this (you better use f:ajax too):

<h:commandButton name="RegisterButton" id="RegisterButton" 
    styleClass="submitbutton"
    value="Register"
    action="#{registrationAction.registerUser}">
    <f:ajax execute="@form" render="@form" />
    <f:actionListener type="org.omnifaces.eventlistener.ResetInputAjaxActionListener"/>
</h:commandButton>

Also , take a look at this BalusC answer How can I populate a text field using primefaces ajax after validation errors occur?

Ushaushant answered 21/11, 2012 at 6:42 Comment(1)
Already i went through those posts, But here the problem is We are not using ajax, And as it is a large scale application, i have to change in all xhtml pages. Is there a way i can achieve the same thing without ajax.Amino
A
0

After a long research, i did not found any way to implement this in JSF. So i have used jQuery to handle it client side, May be this answer is not a best solution, but useful for at least someone who need the solution.

Here the dropdown value will be displayed a old value, but it still shows validation error for the dropdown. In the above xhtml page , if you look into dropdown menu part,

    <h:selectOneMenu id="yourCountry" name="yourCountry"    
                     value="#{shortRegistrationAction.shortRegistrationForm.selectedCountry}"
                     required="true" 
                     styleClass="#{component.valid ? '' : 'text_error'}">
             <f:selectItem itemValue="#{null}" itemLabel="-Select One-" />
             <f:selectItems value="#{registrationAction.countryList}" />
</h:selectOneMenu>

Even it display old value for validation failed case, still the styleClass becomes text_error. I have added the following code in my xhtml page, after closing of <h:body> tag. i.e. (</h:body>) It will work for all the drop downs in this specific xhtml page only, however we can place it in a common place like commonTemplate.xhtml to execute it on all pages.

 <script>
    //<![CDATA[
        jQuery(document).ready(function() {
            jQuery("select").each(function () {
                var dropDownClass = jQuery(this).attr('class');
                if(dropDownClass == 'text_error'){
                    jQuery(this).val('');
                }
              });
        });
    //]]>
    </script>
Amino answered 22/11, 2012 at 5:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.