我得到了
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的片段:
<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>
代码完成了应该是的,但是我在第一行得到了上面提到的错误,只有当我点击英格兰并选择国家选择时,我不知道为什么,我在Ajax化代码中编写了相同的任务,并且它运作良好,任何一只手都会感激不尽。
答案 0 :(得分:3)
如果所选项目的Validation Error: Value is not valid
测试未针对列表中的任何可用项目返回equals()
,则会引发错误true
。因此,它基本上有以下两个原因:
equals()
方法丢失或损坏。项值类型为String
,因此其equals()
方法无疑已正确实现(否则会破坏Java世界中的所有内容)。因此原因1可能被划伤。遗留下来的原因2.是的,实际上,由于某些不明原因,你正在清空国家中可用城市的清单。
public List<SelectItem> getCountries() {
cities.removeAll(cities);
// ...
}
这段代码没有意义。当要验证所选国家/地区时,也会调用getter。这样,当稍后要验证时,在可用城市列表中找不到所选城市。顺便说一句,你的getCities()
也没有任何意义。您正在遍历整个地图而不是仅使用Map#get()
。
这一切都只是破解了代码设计。 Getters不应该包含任何业务逻辑。 Getters应该只返回bean属性。那些bean属性应该在(post)构造函数或action(listener)方法之前很久就已经初始化了。
如何解决这个问题是一个很好的第二个问题。 <h:selectOneMenu valueChangeListener>
在这里基本上被滥用了。这是工作的错误工具。您应该使用<f:ajax listener>
来代替。但如果您真的坚持滥用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;
}
请注意,当您进行某些表单验证时,这仍会导致潜在问题。更好的解决方案是使用<f:ajax>
代替。
答案 1 :(得分:1)
摆脱immediate="true"
和onchange="submit()"
添加
<f:ajax render="city"/>
在您的第一个<h:selectOneMenu
<h:selectOneMenu value="#{countriesAndCities.selectedCountry}" valueChangeListener="#{countriesAndCities.checkSelectedCountry}">
<f:selectItems value="#{countriesAndCities.countries}"></f:selectItems>
<f:ajax render="city"/>
</h:selectOneMenu>
答案 2 :(得分:1)
我建议你在吸气剂中减少处理(阅读:无处理)。如果出于任何原因,绑定到组件的数据源的内容在请求中被修改,则JSF将抛出验证错误,作为软安全功能。将这些列表的填充移动到生命周期钩子(一个公共的void no-args方法,注释为@PostConstruct
),它将在bean被上下文实例化之后立即运行
我假设您为了ajax(糟糕的设计)而使用会话范围的bean支持您的视图。将该bean更改为@ViewScoped
以平滑您的设计并享受您的ajax处理