#cc.clientId 在升级到 JSF 2.2 后在错误的组合中评估

Posted

技术标签:

【中文标题】#cc.clientId 在升级到 JSF 2.2 后在错误的组合中评估【英文标题】:#cc.clientId evaluated in wrong composite after upgrading to JSF 2.2#cc.clientId 在升级到 JSF 2.2 后在错误的组合中评估 【发布时间】:2014-11-18 23:42:38 【问题描述】:

我有一个用 JSF 2.0 + PrimeFaces 3.4 编写的标签库,现在我正在尝试更新到 JSF 2.2 和 PrimeFaces 4.0。 但是我意识到传递给组件的属性值是在复合组件中评估的,它会导致渲染的 id 错误。

enum.xhtml(复合组件)

<cc:interface>
           <cc:attribute name="render" default="@this"/>
            .....
</cc:interface>
<cc:implementation>
  <h:selectOneMenu ......../>
  <p:ajax update="#cc.attrs.render" process="#cc.attrs.execute" />  
</cc:implementation>

用法:

<t:enum id="authenticationSource" value="#authenticationStrategy" .....
  render=":#cc.clientId:tabView:passwordVisibility"/>

渲染属性值为:#cc.clientId:tabView:passwordVisibility,应该是

:j_idt1:j_idt3:j_idt5:editorDialog:j_idt39:j_idt40:tabView:passwordVisibility`

但它被评估为

:j_idt1:j_idt3:j_idt5:editorDialog:j_idt39:j_idt40:tabView:autheticationSource:tabView:passwordVisibility

render 的属性值在复合组件中进行评估,并导致错误。它应该在使用它的地方进行评估,就像在 JSF 2.0 中一样。 是否有任何配置属性或任何东西可以克服这个错误。

我正在使用 Wildfly 8.1.0-Final

【问题讨论】:

也许t:enum 周围的任何元素都变成了命名容器?是否有 ID 为 autheticationSource 的元素? 【参考方案1】:

这个组合的设计不正确。您不应该在复合上下文之外使用#cc.clientId。更一般地说,您不应该从复合材料外部了解复合材料的内部结构。复合材料本身应该担心这一点。

如果您将复合组件相互嵌套,此构造将失败。然后#cc 将实际引用“当前”复合组件。也许您依赖于旧 JSF 实现中的一个错误,其中 #cc 范围在嵌套复合组件之后没有被正确清除(即,它将引用最后分配的值而不是当前上下文中可用的值)。

也许您只是为了错误的目的而过度使用复合组件的受害者,并且仅仅是因为与常规标记文件/包含相比的零配置性质。有关何时使用一个或另一个的详细信息,请访问When to use <ui:include>, tag files, composite components and/or custom components? 重点是,仅当您想将一堆密切相关的组件绑定到一个 single bean 时才使用组合属性,因此当然不是具有多个属性的“完整” bean。

如果您绝对肯定复合材料是满足您要求的正确解决方案,并且/或者您已相应地重构复合材料以消除上述误用,那么有 2 种可能的方法可将客户端行为应用于复合组件,取决于具体的功能要求(如果需要,您甚至可以将这两种方式结合起来)。

    如果您想让复合 ajax 渲染组件在复合之外,请将 &lt;p:ajax&gt;(或 &lt;f:ajax&gt;)外部化为 &lt;cc:clientBehavior&gt;

    <cc:interface>
        <cc:clientBehavior name="myCustomEventName" targets="idOfTargetComponent" event="valueChange" />
        ...
    </cc:interface>
    <cc:implementation>
        <h:selectOneMenu id="idOfTargetComponent" ...>
            <f:selectItems ... />
        </h:selectOneMenu>
    </cc:implementation>
    

    用作:

    <t:enum ...>
        <p:ajax event="myCustomEventName" update=":absoluteClientIdOfComponentOUTSIDEComposite" />
    </t:enum>
    <x:someComponent id="idOfComponentOUTSIDEComposite" />
    

    如果你想让复合 ajax-render 一个组件内部复合,然后让复合自己做这一切。

    <cc:interface>
        ...
    </cc:interface>
    <cc:implementation>
        <h:selectOneMenu ...>
            <f:selectItems ... />
            <p:ajax update="idOfComponentINSIDEComposite" />
        </h:selectOneMenu>
        <x:someComponent id="idOfComponentINSIDEComposite" />
    </cc:implementation>
    

    并以通常的方式使用它:

    <t:enum ... />
    

【讨论】:

对我来说,这与零配置无关。它是关于能够定义一个接口,而不是一堆 ui:params 甚至不适用于正确的方法表达式。我想念 facelet 模板中的客户行为、行动来源和价值持有者。 方法表达式和动作来源:这个问题已知,使用&lt;o:methodParam&gt;。客户端行为:只需使用&lt;ui:define/insert&gt;。价值持有者:应该工作。

以上是关于#cc.clientId 在升级到 JSF 2.2 后在错误的组合中评估的主要内容,如果未能解决你的问题,请参考以下文章

我应该使用带有 render 属性的 ui:fragment 来有条件地在带有 JSF 2.2 的 Facelets 中呈现 HTML 标记吗?

在 JBoss 5.1.1 上将 JSF 从 1.2 升级到 2.1

如何使用指定版本2.3的JSF Facet创建Eclipse动态Web项目?

升级到 JSF 2.3 后,@Inject 在 @FacesConverter 中不起作用

JSF-2.3 找不到我的 @Named CDI-1.2 托管 bean

升级到 jsf2 后的 ViewExpiredException