10

我正在尝试制作 4 个依赖/级联选择组件。在这个问题中,选择组件恰好是 a <h:selectOneMenu>,但这当然适用于从UISelectOne/UISelectMany超类扩展的任何其他类型的选择组件,例如<h:selectManyCheckbox>或 PrimeFaces<p:selectCheckboxMenu><p:selectManyMenu>

当用户从第一个菜单中选择一个项目时,第二个菜单将显示依赖数据,当用户从第二个菜单中选择项目时,第三个菜单将显示依赖数据,依此类推。

用户只会在第一个菜单上看到项目,而其他项目将是空白的。如果他在第一个菜单上选择一个项目,第二个将显示数据,但第三个和第四个将保持空白,依此类推。用户最终必须从所有 4 个菜单中选择条目。

<h:selectOneMenu id="first" value="#{nodes.selectState}">
    <f:selectItems value="#{nodes.stateList}"/>
    <f:ajax render="second">
</h:selectOneMenu>
<h:selectOneMenu id="second" value="#{nodes.selectCity}">
    <f:selectItems value="#{nodes.cityList}"/>
    <f:ajax render="third">
</h:selectOneMenu>
<h:selectOneMenu id="third" value="#{nodes.selectRegion}">
    <f:selectItems value="#{nodes.regionList}"/>
    <f:ajax render="fourth">
</h:selectOneMenu>
<h:selectOneMenu id="fourth" value="#{nodes.selectStation}">
    <f:selectItems value="#{nodes.stationList}"/>
</h:selectOneMenu>

节点豆

private String selectState; //+setters, getters
private String selectCity; //+setters, getters
private String selectRegion; //+setters, getters
private String selectStation; //+setters, getters
private List<SelectItem> stateList; //+setters, getters
private List<SelectItem> cityList; //+setters, getters
private List<SelectItem> regionList; //+setters, getters
private List<SelectItem> stationList; //+setters, getters

public getStateList(){
    stateList= new ArrayList<SelectItem>();
    stateList.add(new SelectItem("A"));
}

public getCityList(){
    CityList= new ArrayList<SelectItem>();
    if(selectState.equals("A")){
        CityList.add(new SelectItem("B"));
    }
}

public getRegionList(){
    RegionList= new ArrayList<SelectItem>();
    if(selectCity.equals("B")){
        RegionList.add(new SelectItem("C"));
   }
}

public getStationList(){
    StationList= new ArrayList<SelectItem>();
    if(selectRegion.equals("C")){
        StationList.add(new SelectItem("D"));
    }
}

它仅适用于前 2 个菜单。其他 2 个菜单获取null值。

4

4 回答 4

10

将 bean 放在视图范围内,并摆脱 getter 方法中的任何业务逻辑。

bean 必须放在视图范围内,以便为后续回发记住所有先前的选择和新的可用项目,否则当 JSF 需要根据先前选择中预填充的可用项目列表验证所选项目时,事情将失败,或者当例如rendered属性取决于仅在先前请求中设置的条件时。

getter 方法可能不包含任何业务逻辑,因为它们也将在验证阶段被调用。您应该使用<f:ajax listener>/<p:ajax listener>来执行基于更改的业务逻辑。您还应该在侦听器方法中明确清除子选择组件的选定值。您可以使用<f:ajax render>/<p:ajax update>来更新子选择组件的内容。

因此,所以:

<h:selectOneMenu id="state" value="#{nodes.selectedState}">
    <f:selectItem itemValue="#{null}" itemLabel="-- select --" />
    <f:selectItems value="#{nodes.availableStates}" />
    <f:ajax listener="#{nodes.changeState}" render="city region station" />
</h:selectOneMenu>
<h:selectOneMenu id="city" value="#{nodes.selectedCity}">
    <f:selectItem itemValue="#{null}" itemLabel="-- select --" />
    <f:selectItems value="#{nodes.availableCities}" />
    <f:ajax listener="#{nodes.changeCity}" render="region station" />
</h:selectOneMenu>
<h:selectOneMenu id="region" value="#{nodes.selectedRegion}">
    <f:selectItem itemValue="#{null}" itemLabel="-- select --" />
    <f:selectItems value="#{nodes.availableRegions}" />
    <f:ajax listener="#{nodes.changeRegion}" render="station" />
</h:selectOneMenu>
<h:selectOneMenu id="station" value="#{nodes.selectedStation}">
    <f:selectItem itemValue="#{null}" itemLabel="-- select --" />
    <f:selectItems value="#{nodes.availableStations}" />
</h:selectOneMenu>

@Named
@ViewScoped
public class Nodes {

    private String selectedState; // getter+setter
    private String selectedCity; // getter+setter
    private String selectedRegion; // getter+setter
    private String selectedStation; // getter+setter
    private List<SelectItem> availableStates; // getter (no setter necessary!)
    private List<SelectItem> availableCities; // getter (no setter necessary!)
    private List<SelectItem> availableRegions; // getter (no setter necessary!)
    private List<SelectItem> availableStations; // getter (no setter necessary!)

    @EJB
    private SomeService someService;

    @PostConstruct
    public void init() {
        availableStates = someService.listStates();
    }

    public void changeState(AjaxBehaviorEvent event) {
        availableCities = someService.listCities(selectedState);
        selectedCity = selectedRegion = selectedStation = null;
        availableRegions = availableStations = null;
    }

    public void changeCity(AjaxBehaviorEvent event) {
        availableRegions = someService.listRegions(selectedCity);
        selectedRegion = selectedStation = null;
        availableStations = null;
    }

    public void changeRegion(AjaxBehaviorEvent event) {
        availableStations = someService.listStations(selectedRegion);
        selectedStation = null;
    }

    // Generate necessary getters+setters here. You should not change them.
}

也可以看看:

于 2013-05-06T11:22:42.133 回答
-1

您的代码中存在拼写错误。对于第三个菜单,您将 id 名称指定为“first”而不是“third”。可能是因为那个问题。

于 2013-05-07T09:26:16.560 回答
-1

试试这个,它可以帮助你

通过使用--Select City--、--Select Region--、--Select Station--来避免空指针异常。

    public getStateList(){
    stateList= new ArrayList<SelectItem>();
    stateList.add(new SelectItem("A"));
    }

    public getCityList(){
    CityList= new ArrayList<SelectItem>();
    if(selectState.equals("A"))
    {
      CityList.add(new SelectItem("B"));
    }
    else
    {
      CityList.add(new SelectItem("--Select City--"));
      selectCity = "--Select City--";
    }

    public getRegionList(){
    RegionList= new ArrayList<SelectItem>();
    if(selectCity.equals("B"))
    {
      RegionList.add(new SelectItem("C"));
    }
    else
    {
      RegionList.add(new SelectItem("--Select Region--"));
      selectRegion = "--Select Region--";
    }
    }

    public getStationList(){
    StationList= new ArrayList<SelectItem>();
    if(selectRegion.equals("C"))
    {
       StationList.add(new SelectItem("D"));
    }
    else
    {
      StationList.add(new SelectItem("Select Station"));
      selectStation = "--Select Station--";
    }
    }
于 2013-05-05T08:41:21.070 回答
-4

你正面临这个问题,因为你有两次id="first"。解决这个问题,它应该可以工作。

于 2016-03-26T07:09:56.133 回答