【问题标题】:Using depending selection lists in request scope在请求范围内使用依赖选择列表
【发布时间】:2010-09-01 09:32:44
【问题描述】:

我们不断从用户那里得到的一个问题是选择(下拉列表或多选)具有依赖值。例如,用户会选择一个国家/地区,然后系统会使用该国家/地区的城市填充城市下拉列表。

我已经在会话(或会话范围)中经常进行这项工作,但现在,对于真正的轻量级场景,我希望让它在请求范围内工作。

这里有一些显示问题的虚拟代码(通常我们会使用 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)。

关于如何解决这个问题的任何想法,甚至是否可能?

【问题讨论】:

    标签: java jsf


    【解决方案1】:

    是的,您想在第 2/3 阶段根据第一个下拉列表的选定选项预填充第二个下拉列表,远远早于 JSF 完成更新模型值阶段,因此 selectedSourceValue 仍然是 null。基本上有两种方法可以解决这个问题:

    1. 从请求参数映射中获取提交的源值作为请求参数。

      selectedSourceValue = (Integer) externalContext.getRequestParameterMap().get("clientId");
      

      然而这很讨厌。

    2. 将下拉组件绑定到UIInput属性,并使用其getSubmittedValue()方法获取提交的值。

      <h:selectOneMenu binding="#{bean.sourceMenu}">
      

      private UIInput sourceMenu; // +getter +setter
      

      然后在getDependentValues()

      if (selectedSourceValue == null && sourceMenu.getSubmittedValue() != null) {
          selectedSourceValue = Integer.valueOf(sourceMenu.getSubmittedValue());
          // ...
      }
      

      更多的工作,但更抽象。

    【讨论】:

    • 感谢您的回答。不过,我现在正在做的项目非常有活力,而且很难融入这一点。我做了另一个解决方法(这也很hacky,但考虑到项目的性质仍然可以)。我会把它作为一个回答发布。
    【解决方案2】:

    我认为,您应该寻找基于 ajax 的组件(Icefaces 允许这种技巧,可能是richfaces、primefaces、jsf2 (f:ajax) 等)。或者在保存按钮 actionListener 中使用验证(事实证明,它更加灵活,至少在我的项目中 + 你总是可以删除 ajax 以避免在基于 ajax 的组件使用 partialSubmit=true 的情况下向服务器发送大量请求)。

    【讨论】:

    • 我们已经在使用 Richfaces。但如前所述,这并没有真正改变问题的核心。在 actionalistener 中进行验证不是解决方案;无论如何,它不会阻止 jsf 进行自己的验证。 (现在我什至不需要任何验证)。
    • 1.jsf 没有必要的验证。有转换器,但我不认为你的意思是他们。 2.你是在 selectBoxes 中使用 partialSubmit 属性,还是使用 Richfaces 的 ajax 属性?
    • 是的,确实如此。一个是验证所选值实际上是一个选项。是的,我们正在使用 ajaxSingle,我认为这是同一件事。
    【解决方案3】:

    如果你使用的是 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

    【讨论】:

    • 我在 JSF1.2 上,但这仍然不是问题的答案。
    【解决方案4】:

    我最终解决了这个问题,将 UISelectMany 子类化为不检查提交的值是否是列表的一部分。这行得通,在我们的场景中,不会受到伤害。

    【讨论】:

      【解决方案5】:

      如果你写

      @Scope("request")
      

      试一试

      @RequestScoped .
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-04-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-20
        • 1970-01-01
        • 2019-08-27
        • 1970-01-01
        相关资源
        最近更新 更多