【问题标题】:Validation Error: Value is not valid on cascasing h:selectOneMenu [duplicate]验证错误:值在级联 h 时无效:selectOneMenu [重复]
【发布时间】:2012-11-22 06:03:27
【问题描述】:

我明白了

j_idt7:city: 验证错误:值无效

切入正题,ManagedBean 代码:

 //few imports here
 @ManagedBean
 @SessionScoped
 public class CountriesAndCities implements Serializable{
 private List<SelectItem> countries;
 private List<SelectItem> cities;
 private  Map<String,List> m;
 private String selectedCountry;

 public String getSelectedCountry() {
return selectedCountry;
 }

 public void setSelectedCountry(String selectedCountry) {
this.selectedCountry = selectedCountry;
 }

 public CountriesAndCities(){
countries = new ArrayList<SelectItem>();
cities = new ArrayList<SelectItem>();
m = new HashMap<String,List>();
m.put("France", Arrays.asList("paris","marseille"));
m.put("England", Arrays.asList("Munchester","liverpoor"));

 }

 public  List<SelectItem> getCountries(){   
cities.removeAll(cities);
countries.removeAll(countries); 
countries.add(new SelectItem("select country"));
for(Map.Entry<String, List> entry: m.entrySet()){
    countries.add(new SelectItem(entry.getKey()));
    }

return countries;
 }
 public List<SelectItem> getCities(){   
for(Map.Entry<String, List> entry: m.entrySet())
      {if(entry.getKey().toString().equals(selectedCountry)){
        cities.addAll(entry.getValue());
        break;
    }
}
return cities;
 }
 public void checkSelectedCountry(ValueChangeEvent event){
selectedCountry = event.getNewValue().toString();   
 }

这是我的 .xhtml 的 sn-p :

 <h:selectOneMenu immediate="true" value="#{countriesAndCities.selectedCountry}" 
 onchange="submit()" valueChangeListener="#{countriesAndCities.checkSelectedCountry}">
 <f:selectItems value="#{countriesAndCities.countries}"></f:selectItems>
 </h:selectOneMenu>
 <br/>
 <h:selectOneMenu id="city">
 <f:selectItems value="#{countriesAndCities.cities}"></f:selectItems>
 </h:selectOneMenu>     
 </h:form>

代码做了应该做的事情,但是我在第一行得到了上面提到的错误,只有当我单击 England 并选择国家选项时,我不知道为什么,我在 Ajaxized 代码中编写了相同的任务,并且它工作得很好,任何手都会感激不尽。

【问题讨论】:

    标签: validation jsf-2 selectonemenu


    【解决方案1】:

    当所选项目的equals() 测试未针对列表中的任何可用项目返回true 时,将引发错误Validation Error: Value is not valid。所以,基本上有以下两个原因:

    1. 项目值类型的equals() 方法丢失或损坏。
    2. 在提交期间可用项目列表发生了不兼容的更改。

    item 的值类型是String,所以它的equals() 方法无疑是正确实现的(否则它会破坏Java 世界中的一切)。所以原因1可能会被划伤。剩下的原因 2。是的,确实,由于某些不清楚的原因,您正在清空国家/地区的可用城市列表。

    public List<SelectItem> getCountries() {   
        cities.removeAll(cities);
        // ...
    }
    

    这段代码没有意义。当要验证所选国家/地区时,也会调用 getter。这样,当稍后将要验证所选城市时,无法在可用城市列表中找到所选城市。顺便说一句,您的getCities() 也没有任何意义。您正在遍历整个地图,而不是仅使用 Map#get()

    这一切都是错误的代码设计。 Getter 根本不应该包含任何业务逻辑。 Getter 应该只返回 bean 属性。这些 bean 属性应该早在 (post)constructor 或 action(listener) 方法中就已经预先初始化了。

    如何解决这是一个很好的第二个问题。 &lt;h:selectOneMenu valueChangeListener&gt; 基本上在这里被滥用了。这是工作的错误工具。您应该为此使用&lt;f:ajax listener&gt;。但是,如果您真的坚持滥用valueChangeListener 来完成这项工作,那么您应该按如下方式解决它,即您将ValueChangeEvent 排队到INVOKE_APPLICATION 阶段并在该阶段执行该工作(好像它是一个( ajax) 动作监听方法):

    private List<String> countries;
    private List<String> cities;
    private Map<String, List<String>> countriesAndCities;
    private String selectedCountry;
    
    @PostConstruct
    public void init() {
        countriesAndCities = new LinkedHashMap<String, List<String>>(); // Note: LinkedHashMap remembers insertion order, HashMap not.
        countriesAndCities.put("France", Arrays.asList("paris","marseille"));
        countriesAndCities.put("England", Arrays.asList("Munchester","liverpoor"));
        countries = new ArrayList<String>(countriesAndCities.keySet());
    }
    
    public void checkSelectedCountry(ValueChangeEvent event) { // I'd rename that method name to loadCities() or something more sensible.
        if (event.getPhaseId() != PhaseId.INVOKE_APPPLICATION) {
            // Move the job to the INVOKE_APPLICATION phase. 
            // The PROCESS_VALIDATIONS phase is the wrong phase for the "action listener"-like job.
            event.setPhaseId(PhaseId.INVOKE_APPLICATION);
            event.queue();
            return;
        }
    
        cities = countriesAndCities.get(selectedCountry);
    }
    
    // Getters and setters. Do not change them! They should just get and set properties. Nothing more!
    
    public List<String> getCountries(){   
        return countries;
    }
    
    public List<String> getCities(){   
        return cities;
    }
    
    public String getSelectedCountry() {
        return selectedCountry;
    }
    
    public void setSelectedCountry(String selectedCountry) {
        this.selectedCountry = selectedCountry;
    }
    

    请注意,当您进行一些表单验证时,这仍然会导致潜在的问题。一个更好的解决方案是改用&lt;f:ajax&gt;

    另见:

    【讨论】:

    • 嘿BalusC,谢谢你还不够,我想我太盲目了,让所有这些错误都过去了,但是我尝试了你的代码,得到了这个异常:
    • 别在意上面的评论,我的错误,我重试了你的代码,它运行顺利,你是 JSF 的人 :),继续伟大的工作,非常感谢,先生.
    【解决方案2】:

    我建议您在 getter 中减少处理(阅读:不处理)。如果由于任何原因绑定到组件的数据源的内容在请求中被修改,JSF 将抛出验证错误,作为软安全功能。将这些列表的数量移动到生命周期钩子(一个公共 void 无参数方法,用 @PostConstruct 注释),它将在 bean 被上下文实例化后立即运行

    我假设您为了 ajax(糟糕的设计)而使用会话范围的 bean 来支持您的视图。将该 bean 更改为 @ViewScoped 以平滑您的设计并享受您的 ajax 处理

    【讨论】:

      【解决方案3】:

      摆脱immediate="true"onchange="submit()"

      添加

      <f:ajax render="city"/>
      

      在您的第一个 &lt;h:selectOneMenu

      喜欢这个

      <h:selectOneMenu  value="#{countriesAndCities.selectedCountry}" valueChangeListener="#{countriesAndCities.checkSelectedCountry}">
           <f:selectItems value="#{countriesAndCities.countries}"></f:selectItems>
           <f:ajax render="city"/>
      </h:selectOneMenu>
      

      并阅读此Learning JSF2: Ajax in JSF – using f:ajax tag

      【讨论】:

      • 首先,感谢您抽出宝贵时间,但是如果您仔细阅读了我的问题,您会注意到我说,我已经以 Ajaxized 方式完成了任务,但是我只是想以事件处理的方式来做。
      • 我读过,但不知道 Ajaxized code 等于 using f:ajax
      猜你喜欢
      • 2013-04-09
      • 2011-06-01
      • 2011-10-31
      • 1970-01-01
      • 2011-10-29
      • 2013-01-06
      • 2017-09-04
      • 2011-09-13
      相关资源
      最近更新 更多