【问题标题】:why action in <h:commandLink> doesn't work inside a composite component为什么 <h:commandLink> 中的操作在复合组件中不起作用
【发布时间】:2014-12-18 23:18:43
【问题描述】:

我有一个非常简单的 JSF 2/Facelets 页面,如下所示:

<ui:repeat value="#{myBean.names}" var="_name">
  <h:commandLink value="#{_name}" action="#{myBean.sayHello(_name)}">
    <f:ajax execute="@this"/>
  </h:commandLink>
  <br/>
</ui:repeat>

支持 bean 提供一个带有名称的 java.util.List&lt;String&gt;,而操作方法只是将 "hello &lt;name&gt;" 消息打印到标准输出。

这很好用。我在浏览器中获得了一个名称列表,单击会触发向指定名称打招呼的操作方法。

问题出现了,当我想将此代码放入执行迭代并通过构面呈现实际链接的复合组件中时:

<ui:component xmlns="http://www.w3.org/1999/xhtml"
              xmlns:f="http://xmlns.jcp.org/jsf/core"
              xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
              xmlns:cc="http://xmlns.jcp.org/jsf/composite">
  <cc:interface>
    <cc:attribute name="value" type="java.util.List" required="true" />
    <cc:facet name="content" />
  </cc:interface>
  <cc:implementation>
   <ui:repeat value="#{cc.attrs.value}" var="_name">
     <cc:renderFacet name="content"/>
   </ui:repeat>
  </cc:implementation>
</ui:component>

我是这样使用复合组件的:

<my:myComp value="#{bean.names}">
  <f:facet name="content">
    <h:commandLink value="#{_name}" action="#{bean.sayHello(_name)}">
      <f:ajax execute="@this"/>
    </h:commandLink>
    <br/>
  </f:facet>
</my:myComp>

在浏览器中,我得到一个与以前完全一样的名称列表。但是现在单击链接会呈现"hello null" 消息。所以_name&lt;h:commandLink&gt;value 属性中被正确解析,但在action 属性中却没有。

我也尝试使用actionListener 代替action&lt;f:ajax&gt; 标记中的listener 属性,没有区别。

有人可以对这个问题有所了解吗?

我的环境:

  • WildFly 8.1 与
  • JSF 2.2.6 (Mojarra)

【问题讨论】:

    标签: jsf-2 composite-component


    【解决方案1】:

    在这种情况下,问题与变量的范围有关,@​​987654322@ 在处理&lt;ui:repeat/&gt; 时会评估一次。就我而言,我运行了您的代码,它生成了Hello John,即使它们是我列表中的其他名称。为了解决这个问题,我引入了一个包含_name 值的&lt;f:param/&gt;,并将您的代码修改如下:

        <h:form>
            <my:myComp value="#{bean.names}">
                <f:facet name="content">
                    <h:commandLink value="#{_name}" action="#{bean.sayHello()}">
                        <f:param name="name_" value="#{_name}"/>
                        <f:ajax execute="@this"/>
                    </h:commandLink>
                    <br/>
                </f:facet>
            </my:myComp>
        </h:form>
    

    我还为@RequestScoped bean 修改了sayHello() 方法如下:

    @ManagedProperty(value = "#{facesContext}")
    private FacesContext facesContext;
    
    public void setFacesContext(FacesContext facesContext) {
        this.facesContext = facesContext;
    }
    
    public void sayHello() {
        Map<String, String> params = facesContext.getExternalContext()
                    .getRequestParameterMap();
        String name = params.get("name_");
        System.out.println("Hello " + name);
    }
    

    您可以在 @ViewScoped bean 中将其更改为更短的内容:

     public void sayHello() {
        Map<String, String> params = FacesContext.getCurrentInstance()
                .getExternalContext().getRequestParameterMap();
        String name = params.get("name_");
        System.out.println("Hello " + name);
    }
    

    最终的结果是它正确地打印出名称。

    【讨论】:

    • 感谢您的回复。您的解决方法是有效的,这实际上就是我已经拥有的方法(想稍后发布)。不幸的是,您没有解释细节,为什么变量会被解析一次(为了价值)而不是另一次(为了行动)。这就是我真正感兴趣的内容。请您也提供这些信息吗?
    • 我很确定,那是不同的东西。我的代码在复合组件之外工作,不调用任何设置器。并且该变量似乎已设置,因为我可以输出它的值。除此之外,我尝试在您发布的链接中使用包装器,但行为没有区别。
    • @JohnYearly,我对解决方法投了赞成票。仍然没有回答实际问题。
    猜你喜欢
    • 2012-03-28
    • 1970-01-01
    • 2011-10-14
    • 2018-02-27
    • 1970-01-01
    • 1970-01-01
    • 2023-02-23
    • 2011-09-16
    • 2022-07-17
    相关资源
    最近更新 更多