代码之家  ›  专栏  ›  技术社区  ›  Joeri Hendrickx

在请求范围中使用依赖选择列表

  •  2
  • Joeri Hendrickx  · 技术社区  · 14 年前

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

    我已经在会话(或会话范围)中经常使用这种方法,但是现在,对于一个真正的轻量级场景,我希望它在请求范围内工作。

    下面是一些显示问题的伪代码(通常我们会使用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>
    

    背豆:

    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 (使用太阳RI)。

    关于如何解决这个问题,或者是否有可能?

    5 回复  |  直到 10 年前
        1
  •  1
  •   BalusC    14 年前

    好的,您希望在第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());
          // ...
      }
      

      更多的工作,但更抽象。

        2
  •  0
  •   foret    14 年前

    我认为,您应该寻找基于Ajax的组件(IceFaces允许这种技巧,可能是RichFaces、PrimeFaces、JSF2(f:Ajax)等)。或者在save button actionListener中使用validation(事实证明,它更灵活,至少在我的项目+中,您总是可以删除Ajax,以避免在基于Ajax的组件partialSubmit=true的情况下向服务器发送大量请求)。

        3
  •  0
  •   amorfis    14 年前

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

        4
  •  0
  •   Joeri Hendrickx    14 年前

    最后我通过对uiselectmany进行子类化来解决这个问题,不检查提交的值是否是列表的一部分。这是可行的,在我们的场景中,不会造成伤害。

        5
  •  0
  •   Emre Karataşoğlu    11 年前

    如果你写

    @Scope("request")
    

    试试看吧

    @RequestScoped .