我们不断向用户提出的问题是具有相关值的选择(下拉列表或多选)。例如,用户选择一个国家/地区,然后系统会使用该国家/地区的城市填充城市下拉列表。
我在会话(或会话范围)中经常做这项工作但现在,对于一个真正的轻量级场景,我希望它在请求范围内工作。
这里有一些显示问题的虚拟代码(通常我们会使用A4J填充下拉列表而不进行完全刷新,但问题也可以用普通的jsf来证明):
JSF:
<h:form>
<p>
<h:selectOneMenu value="#{bean.selectedSourceValue}">
<f:selectItems value="#{bean.sourceValues}" />
</h:selectOneMenu>
</p>
<p>
<h:selectOneMenu value="#{bean.selectedDependentValue}">
<f:selectItems value="#{bean.dependentValues}" />
</h:selectOneMenu>
</p>
<p>
<h:commandButton value="submit" />
</p>
</h:form>
支持bean:
public class Bean {
private Integer selectedSourceValue;
private Integer selectedDependentValue;
/**
* @return values for the first selection. Numbers from 1 to 10.
*/
public List<SelectItem> getSourceValues(){
List<SelectItem> r = new ArrayList<SelectItem>();
for(int i=1; i<=10; i++){
r.add(new SelectItem(i));
}
return r;
}
/**
* @return values for the second selection. First ten powers of the selected first value.
*/
public List<SelectItem> getDependentValues(){
if (selectedSourceValue==null) return Collections.emptyList();
List<SelectItem> r = new ArrayList<SelectItem>();
for(int i=1; i<=10; i++){
r.add(new SelectItem((int)Math.pow(selectedSourceValue, i)));
}
return r;
}
// ... snipped some basic getter and setters
}
看起来很简单。问题在于进行第二次选择时。提交第二个下拉列表时,将验证组合。但是在验证阶段,请求范围的bean尚未填充,因此getDependentValues()
返回null。这会导致jsf抛出NoSuchElementException
(使用Sun RI)。
有关如何解决这个问题的想法,甚至是否可能?
答案 0 :(得分:1)
是的,您希望根据第二/第三阶段中第一个下拉列表的选定选项预填充第二个下拉列表,远在JSF完成更新模型值阶段之前,因此selectedSourceValue
仍然是{{ 1}}。基本上有两种方法可以解决这个问题:
从请求参数映射中获取提交的源值作为请求参数。
null
然而这是令人讨厌的。
将下拉组件绑定到selectedSourceValue = (Integer) externalContext.getRequestParameterMap().get("clientId");
属性,并使用其UIInput
方法获取提交的值。
getSubmittedValue()
与
<h:selectOneMenu binding="#{bean.sourceMenu}">
然后在private UIInput sourceMenu; // +getter +setter
getDependentValues()
更多的工作,但更抽象。
答案 1 :(得分:0)
我认为,你应该寻找基于ajax的组件(Icefaces允许这个技巧,可能是richfaces,primefaces,jsf2(f:ajax)等)。或者在保存按钮actionListener中使用验证(事实证明,它更灵活,至少在我的项目中+你总是可以删除ajax以避免在基于ajax的组件使用partialSubmit = true的情况下向服务器发送大量请求)。
答案 2 :(得分:0)
如果您使用的是JSF2,请尝试:
<h:form>
<p>
<h:selectOneMenu id="selectionSource" value="#{bean.selectedSourceValue}">
<f:selectItems value="#{bean.sourceValues}" />
<f:ajax execute="selectionSource" render="dependentSelection"/>
</h:selectOneMenu>
</p>
<p>
<h:selectOneMenu id="dependentSelection" value="#{bean.selectedDependentValue}">
<f:selectItems value="#{bean.dependentValues}" />
</h:selectOneMenu>
</p>
<p>
<h:commandButton value="submit" />
</p>
</h:form>
此处的解决方案:http://pawelstawicki.blogspot.com/2010/03/simple-ajax-with-jsf-20.html
答案 3 :(得分:0)
我最后通过继承UISelectMany来解决它,而不是检查提交的值是否是列表的一部分。这是有效的,在我们的场景中,没有伤害。
答案 4 :(得分:0)
如果你写
@Scope("request")
尝试
@RequestScoped .