我建立了一个复合组件,看起来像这样:
<composite:interface> <composite:attribute name="id" required="false" /> <composite:attribute name="label" required="true" /> </composite:interface> <composite:implementation> <h:panelGroup id="#{cc.attrs.id}"> <fieldset class="fieldset"><legend>${cc.attrs.label}</legend></fieldset> </h:panelGroup> </composite:implementation>
组件正确显示当前标签。
<xyz:comp id="idMyComponent" label="#{someBean.text}"/> ... <a4j:ajax ... render="idMyComponent" /> ...
现在,当执行该动作时,什么也不会发生。但是,当我将Postfix添加到组件中的ID时,它可以正常工作(请参见下文)。
... <composite:implementation> <h:panelGroup id="#{cc.attrs.id}Label"> ...
并使用后缀在render中定义ID:
<xyz:comp id="idMyComponent" label="#{someBean.text}"/> ... <a4j:ajax ... render="idMyComponentLabel" /> ...
有人可以向我解释为什么仅当我在ID中添加后缀时才起作用h:panelGroup吗?
h:panelGroup
这个问题实际上有两个方面。
第一个问题是,<xyz:comp id>实际上指定复合部件的ID 本身 的<cc:implementation>。默认情况下,HTML输出中不显示该位置,因此ajax / JavaScript不能被document.getElementById()and friends 找到。
<xyz:comp id>
<cc:implementation>
document.getElementById()
实际上,<h:panelGroup id="#{cc.attrs.id}">最终您会生成如下所示的HTML输出(右键单击页面和“ 查看源代码” 以自己 查看 ):
<h:panelGroup id="#{cc.attrs.id}">
<span id="idMyComponent:idMyComponent">
第二个“问题”是RichFaces / Ajax4jsf :不仅通过在当前上下文中进行搜索NamingContainer,还通过在所有其他NamingContainer组件中进行搜索,从而通过相对客户端ID(即,不以开头)增强了树中JSF组件的引用/查找。复合组件固有地也是NamingContainer组件。
:
NamingContainer
您的第一次尝试失败了,因为它找到了组合本身而不是面板组,但是JS / ajax却又未能更新,因为id="myComponent"在生成的HTML输出中不存在任何HTML元素。
id="myComponent"
您的第二次尝试成功了,因为它最终找到了真正的面板组(注意:因为它也在所有其他NamingContainer组件中进行了搜索;如果您使用<f:ajax>代替,这仍然会失败<a4j:ajax>)。
<f:ajax>
<a4j:ajax>
解决问题的正确方法不是#{cc.attrs.id}在JSF组件上使用,而是#{cc.clientId}在纯HTML元素上使用。
#{cc.attrs.id}
#{cc.clientId}
<span id="#{cc.clientId}">
(是的,使用一个<span>或<div>代替<h:panelGroup>内部的<cc:implementation>)
<span>
<div>
<h:panelGroup>
这样,JSF可以通过客户端ID找到组件(以便生成正确的ajax响应), 而 JS可以通过客户端ID找到HTML元素(以便基于ajax响应更新正确的HTML元素)。