【问题标题】:JSF2 h:selectOneMenu shows old value when Validation FailedJSF2 h:selectOneMenu 在验证失败时显示旧值
【发布时间】:2012-11-09 05:14:11
【问题描述】:

我有一个包含几个输入字段和一个选择一个菜单的表单。 所有字段都是必填项="true", 名字、姓氏、电子邮件地址、密码、国家/地区。

测试用例 #1: 1) 在所有输入字段中输入值,离开 firstName 字段而不输入任何值,
选择一个国家(例如:美国)并提交表格,我们可以看到错误信息 对于 firstName 字段是必需的。

2) 保持表单原样,离开 firstName 字段而不输入任何值, 然后选择国家“选择一个”,并提交表格。我们可以看到错误信息 对于名字和国家/地区字段,但在下拉列表中没有显示“选择一个”, 它显示美国(之前的选择)。

我对输入字段有同样的问题,但我用转换器解决了。 有没有办法解决这个问题。我在 stackoverflow 中发布了几篇文章,后来才知道这是 mojarra 中的一个错误。

这是我的代码...

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();
    }

}

【问题讨论】:

    标签: jsf jsf-2 facelets


    【解决方案1】:

    经过长时间的研究,我没有找到在 JSF 中实现这一点的任何方法。 所以我用jQuery来处理它的客户端, 可能这个答案不是最佳解决方案,但至少对需要解决方案的人有用。

    这里的下拉列表值将显示一个旧值,但它仍然显示下拉列表的验证错误。 在上面的 xhtml 页面中,如果您查看下拉菜单部分,

        <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>
    

    即使在验证失败的情况下显示旧值,styleClass 仍然会变为 text_error。 在关闭&lt;h:body&gt; 标签后,我在我的 xhtml 页面中添加了以下代码。即(&lt;/h:body&gt;) 它仅适用于该特定 xhtml 页面中的所有下拉菜单,但我们可以将其放置在 commonTemplate.xhtml 等公共位置以在所有页面上执行它。

     <script>
        //<![CDATA[
            jQuery(document).ready(function() {
                jQuery("select").each(function () {
                    var dropDownClass = jQuery(this).attr('class');
                    if(dropDownClass == 'text_error'){
                        jQuery(this).val('');
                    }
                  });
            });
        //]]>
        </script>
    

    【讨论】:

      【解决方案2】:

      看看下面的BalusC博文Reset non-processed input components on ajax update

      您可以将OmniFaces 添加到您的项目中并使用它的ResetInputAjaxActionListener

      所以你必须将你的代码更新为这个(你最好也使用f:ajax):

      <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>
      

      另外,看看这个 BalusC 答案How can I populate a text field using primefaces ajax after validation errors occur?

      【讨论】:

      • 我已经浏览了这些帖子,但这里的问题是我们没有使用 ajax,因为它是一个大型应用程序,我必须在所有 xhtml 页面中进行更改。有没有办法在没有 ajax 的情况下实现同样的目标。
      猜你喜欢
      • 2014-04-16
      • 2012-07-16
      • 2020-03-01
      • 2011-06-14
      • 1970-01-01
      • 1970-01-01
      • 2011-07-29
      • 2012-09-09
      • 1970-01-01
      相关资源
      最近更新 更多