如何在h:selectOneMenu更改时加载和显示依赖的h:selectOneMenu

3
我想创建一个JSF注册表单,其中包含所有国家的选择菜单列表。 我知道使用Java HashMap 实现这很容易,但我不知道如何实现用户从列表中选择自己的国家后,右侧就出现包含该国家城市的第二个选择菜单。 有没有什么有用的例子?
祝一切顺利。
1个回答

14
你可以使用<f:ajax>来实现这个功能。当它嵌套在一个输入组件中,例如<h:selectOneMenu>中,那么默认情况下它将在输入值更改时被调用。您可以指定一个listener方法,该方法可以基于当前输入值预填下一个组件的数据,并且您可以在render中指定该下一个组件的客户端ID以显示预填充的数据。
<h:selectOneMenu value="#{bean.country}">
    <f:selectItems value="#{bean.countries}" />
    <f:ajax listener="#{bean.changeCountry}" render="cities" />
</h:selectOneMenu>
<h:panelGroup id="cities">
    <h:selectOneMenu value="#{bean.city}" rendered="#{not empty bean.cities}">
        <f:selectItems value="#{bean.cities}" />
    </h:selectOneMenu>
</h:panelGroup>

该Bean必须至少处于视图范围中(而不是请求范围):

@ManagedBean
@ViewScoped
public class Bean implements Serializable {

    private String country; // +getter+setter
    private String city; // +getter+setter
    private List<String> countries; // +getter
    private List<String> cities; // +getter

    @EJB
    private LocationService locationService;

    @PostConstruct
    public void init() {
        countries = locationService.getCountries();
    }

    public void changeCountry() {
        cities = locationService.getCities(country);
    }

    // ...
}
当然,你也可以使用一个Map<String, String>来替代List<String>。Map中的键变成选项标签,值则成为选项值。需要注意的是,一个HashMap本质上是无序的。你可以使用LinkedHashMapMap插入顺序展示项目。

另请参阅:


+1 给 @BalusC,答案非常清晰,并且 你的博客 更深入地解释了它。 :) 如果有100个用户访问同一页,我会浪费内存创建100个不同的对象!是否有优化方式可以在应用程序级别使用该对象? - 09Q71AO534
@09Q71AO534:只需将应用程序范围的数据(例如#{bean.countries})放入应用程序范围的Bean中,并利用JPA第二级缓存来处理城市即可。 - BalusC
@BalusC,你知道我需要插入哪个Java包来使用private LocationService locationService;吗? - Peter Penzov
@Peter:这只是你自己的服务类。名称只是举例,就像“Bean”一样。 - BalusC
@BalusC,是否可以在不实际提交(和设置)第一个下拉菜单的情况下更改第二个下拉菜单?(通过使用execute = "@ none")。如果我的表单在可以关闭/取消的弹出窗口中,我不希望将任何第一个(ajax)下拉菜单的更改应用于我的模型,直到使用“保存”提交按钮。 - Xavier Dury

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接