日期:2014-05-16  浏览次数:20409 次

JSF/Facelets 复合组件 cc:renderFacet 的问题与解决方案
复合组件 (composite component) 以下简称cc。

在 JSR-314 的邮件列表中有个讨论,http://lists.jboss.org/pipermail/jsr-314-open-mirror/2009-September/001526.html

问题的焦点是,cc 被设计为一个黑盒结构,组件如果内部含有 naming container,那么它 *应该* 不要在页面的组件实例中插入”奇怪“的 client id。

比如说,child.xhtml:
  <cc:implementation>
     <h:form id="xyz">
         <cc:renderFacet ..>

以及
  <my:child id="aaa">
    <f:facet>
       <commandButton id="c">

那么,commandButton 的 clientId 应该是 aaa:c,而不是 aaa:xyz:c。

但是,问题并不仅仅在于 client id。如果是 client id 变得更加简短,那么页面作者倒是更省心了。

原因就在于,client id 是反应 component tree 的,也就是说,commandButton 在 renderFacet 的机制下,并不是挂接到 form 下面,而是挂在了 my:child 的下面。也就是说 renderFacet 将 f:facet 重新定向到 cc 上了。

那么能不能不要重新定向呢?

简单的说,不可以。但是,有几个特殊情况:

  1. 如果 cc 里面要用到 f:facet,而页面上传递 f:facet 给 cc 里面的同名 f:facet,那么你可以用 cc:insertFacet。

  2. 用 cc:insertChildren.

这里, cc:insertFacet 和 cc:insertChildren 不会重定向。但是, cc:insertFacet 只能用来传递 f:facet,而 cc:insertChildren 只有一个锚点。

那么能不能用 insertChildren 的方式插入一个 facet 呢?

事实证明是可以的,经过摸索通过自定制一个 tag handler,来模拟 insertFacet 的行为,但绕过外层的 f:facet 即可。

源代码请参考我在 SO 上的回复:http://stackoverflow.com/questions/7891650/using-compositeinsertfacet-renderfacet-does-not-work-inside-tdatatable/9091313#9091313