提问人:perissf 提问时间:12/26/2011 最后编辑:BalusCperissf 更新时间:7/1/2022 访问量:182106
如何找出ajax更新/渲染组件的客户端ID?找不到从“bar”引用表达式“foo”的组件
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
问:
以下代码的灵感来自 PrimeFaces DataGrid + DataTable 教程,并放入驻留在 a of a 中。这是代码的内部部分(从组件开始);外部是微不足道的。<p:tab>
<p:tabView>
<p:layoutUnit>
<p:layout>
p:tab
<p:tabView id="tabs">
<p:tab id="search" title="Search">
<h:form id="insTable">
<p:dataTable id="table" var="lndInstrument" value="#{instrumentBean.instruments}">
<p:column>
<p:commandLink id="select" update="insTable:display" oncomplete="dlg.show()">
<f:setPropertyActionListener value="#{lndInstrument}"
target="#{instrumentBean.selectedInstrument}" />
<h:outputText value="#{lndInstrument.name}" />
</p:commandLink>
</p:column>
</p:dataTable>
<p:dialog id="dlg" modal="true" widgetVar="dlg">
<h:panelGrid id="display">
<h:outputText value="Name:" />
<h:outputText value="#{instrumentBean.selectedInstrument.name}" />
</h:panelGrid>
</p:dialog>
</h:form>
</p:tab>
</p:tabView>
当我单击 时,代码停止工作并给出消息:<p:commandLink>
找不到从“tabs:insTable:select”引用表达式“insTable:display”的组件。
当我尝试使用相同的方法时,它会失败,并显示一条不同的消息,基本上告诉相同:<f:ajax>
<f:ajax>
包含未知 ID “insTable:display” 无法在组件 “tabs:insTable:select” 的上下文中找到它
当它发生在另一个 Ajax 回发期间,并且 JSF 项目阶段设置为 ,则它会失败,并显示 JavaScript 警报,并显示以下消息:Development
malformedXML:更新期间:insTable:未找到显示
这是怎么造成的,我该如何解决?
答:
首先:据我所知,将对话框放在 TabView 中是一种不好的做法......你最好把它拿出来......
现在来回答你的问题:
对不起,我花了一些时间才明白你到底想要实现什么,
刚才我自己在我的网络应用程序上做了,它有效
正如我之前所说,将 p:dialog 放在 'p:tabView ,
按照您最初的建议保留 p:dialog:
<p:dialog modal="true" widgetVar="dlg">
<h:panelGrid id="display">
<h:outputText value="Name:" />
<h:outputText value="#{instrumentBean.selectedInstrument.name}" />
</h:panelGrid>
</p:dialog>
p:commandlink 应该看起来像这样(我所做的只是更改更新属性)
<p:commandLink update="display" oncomplete="dlg.show()">
<f:setPropertyActionListener value="#{lndInstrument}"
target="#{instrumentBean.selectedInstrument}" />
<h:outputText value="#{lndInstrument.name}" />
</p:commandLink>
这同样适用于我的 Web 应用程序,如果它不适合您,那么我想您的 Java Bean 代码中有问题......
评论
尝试更改为 .我相信你不能像那样用表单 ID 作为 id 的前缀。update="insTable:display"
update="display"
评论
这是因为选项卡也是一个命名容器......你的更新应该是 你也可以做的是把你的对话框放在窗体外面,仍然在标签内,然后它就是:update="Search:insTable:display"
update="Search:display"
在 HTML 输出中查找实际的客户端 ID
您需要查看生成的 HTML 输出以找到正确的客户端 ID。 在浏览器中打开页面,右键单击并查看源代码。找到感兴趣的 JSF 组件的 HTML 表示形式,并将其作为客户端 ID。您可以根据当前命名容器以绝对或相对方式使用它。请参阅下一章。id
注意:如果它碰巧包含迭代索引,如 、 等(因为它位于迭代组件内部),那么您需要意识到并不总是支持更新特定的迭代轮次。有关这方面的更多详细信息,请参阅答案底部。:0:
:1:
记住组件并始终为它们提供固定的 IDNamingContainer
如果要通过ajax process/execute/update/render引用的组件位于同一NamingContainer
父级中,则只需引用其自己的ID。
<h:form id="form">
<p:commandLink update="result"> <!-- OK! -->
<h:panelGroup id="result" />
</h:form>
如果它不在同一个 中,那么您需要使用绝对客户端 ID 引用它。绝对客户端 ID 以分隔符开头,默认情况下为 。NamingContainer
NamingContainer
:
<h:form id="form">
<p:commandLink update="result"> <!-- FAIL! -->
</h:form>
<h:panelGroup id="result" />
<h:form id="form">
<p:commandLink update=":result"> <!-- OK! -->
</h:form>
<h:panelGroup id="result" />
<h:form id="form">
<p:commandLink update=":result"> <!-- FAIL! -->
</h:form>
<h:form id="otherform">
<h:panelGroup id="result" />
</h:form>
<h:form id="form">
<p:commandLink update=":otherform:result"> <!-- OK! -->
</h:form>
<h:form id="otherform">
<h:panelGroup id="result" />
</h:form>
例如,命名容器
组件包括 、 、 、(因此,所有复合组件)等。通过查看生成的 HTML 输出,您可以轻松识别它们,它们的 ID 将附加到所有子组件生成的客户端 ID 之前。请注意,当它们没有固定的 ID 时,JSF 将使用自动生成的 ID 格式。您绝对应该通过给他们一个固定的 ID 来避免这种情况。在开发过程中,OmniFaces NoAutoGeneratedIdViewHandler
可能会有所帮助。<h:form>
<h:dataTable>
<p:tabView>
<cc:implementation>
j_idXXX
如果你知道要找到有问题的 javadoc,那么你也可以在那里检查它是否实现了 NamingContainer
接口。例如,HtmlForm
(后面标签)显示它实现了,但 HtmlPanelGroup
(后面标签)没有显示它,因此它没有实现。这是所有标准组件的javadoc,这是PrimeFaces的javadoc。UIComponent
UIComponent
<h:form>
NamingContainer
UIComponent
<h:panelGroup>
NamingContainer
解决您的问题
因此,在您的情况下:
<p:tabView id="tabs"><!-- This is a NamingContainer -->
<p:tab id="search"><!-- This is NOT a NamingContainer -->
<h:form id="insTable"><!-- This is a NamingContainer -->
<p:dialog id="dlg"><!-- This is NOT a NamingContainer -->
<h:panelGrid id="display">
生成的 HTML 输出如下所示:<h:panelGrid id="display">
<table id="tabs:insTable:display">
您需要将其完全用作客户端 ID,然后在以下位置以 for usage 为前缀:id
:
update
<p:commandLink update=":tabs:insTable:display">
引用外部 include/tagfile/composite
如果此命令链接位于 include/tagfile 内部,而目标位于其外部,因此您不一定知道当前命名容器的命名容器父级的 ID,则您可以通过如下方式动态引用它:UIComponent#getNamingContainer()
<p:commandLink update=":#{component.namingContainer.parent.namingContainer.clientId}:display">
或者,如果此命令链接位于复合组件内部,而目标位于复合组件外部:
<p:commandLink update=":#{cc.parent.namingContainer.clientId}:display">
或者,如果命令链接和目标都位于同一复合组件中:
<p:commandLink update=":#{cc.clientId}:display">
另请参阅在模板中获取父命名容器的 ID for in render / update 属性
它是如何在幕后工作的
这一切都在 UIComponent#findComponent()
javadoc 中被指定为“搜索表达式”:
搜索表达式由标识符(与 的 id 属性完全匹配)或由字符值链接的一系列此类标识符组成。搜索算法应按如下方式运行,但只要最终结果相同,就可以使用替代算法:
UIComponent
UINamingContainer#getSeparatorChar
- 确定将成为搜索基础的,只要满足以下条件之一,就停止:
UIComponent
- 如果搜索表达式以分隔符开头(称为“绝对”搜索表达式),则基值将是组件树的根。前导分隔符将被剥离,搜索表达式的其余部分将被视为“相对”搜索表达式,如下所述。
UIComponent
- 否则,如果这是一个,它将作为基础。
UIComponent
NamingContainer
- 否则,请搜索此组件的父级。如果遇到 a,它将是基础。
NamingContainer
- 否则(如果遇到 no),根将是基数。
NamingContainer
UIComponent
- 搜索表达式(可能在上一步中修改)现在是一个“相对”搜索表达式,用于在基本组件的范围内查找 ID 匹配的组件(如果有)。比赛按如下方式进行:
- 如果搜索表达式是简单标识符,则将此值与 id 属性进行比较,然后递归地遍历基的分面和子项(除非找到后代,则不搜索其自己的分面和子项)。
UIComponent
NamingContainer
- 如果搜索表达式包含多个由分隔符分隔的标识符,则第一个标识符用于查找前一个项目符号点中的规则。然后,将调用 this 方法,传递搜索表达式的其余部分。
NamingContainer
findComponent()
NamingContainer
请注意,PrimeFaces 也遵循 JSF 规范,但 RichFaces 使用“一些额外的例外”。
“reRender”使用算法(有一些额外的例外)在组件树中查找组件。
UIComponent.findComponent()
这些额外的异常没有详细描述,但众所周知,相对组件 ID(即不以 开头的 ID)不仅在最接近的父项的上下文中搜索,而且还在同一视图中的所有其他组件中搜索(顺便说一句,这是一项相对昂贵的工作)。:
NamingContainer
NamingContainer
从不使用prependId="false"
如果这一切仍然不起作用,请验证您是否未使用 .在处理 ajax 提交和渲染期间,这将失败。另请参阅此相关问题:带有 prependId=“false” 的 UIForm 会中断 <f:ajax render>。<h:form prependId="false">
引用迭代组件的特定迭代轮次
很长一段时间以来,不可能在迭代组件中引用特定的迭代项,例如:<ui:repeat>
<h:dataTable>
<h:form id="form">
<ui:repeat id="list" value="#{['one','two','three']}" var="item">
<h:outputText id="item" value="#{item}" /><br/>
</ui:repeat>
<h:commandButton value="Update second item">
<f:ajax render=":form:list:1:item" />
</h:commandButton>
</h:form>
但是,由于Mojarra 2.2.5开始支持它(它只是停止验证它;因此您将永远不会再遇到提到的问题中的异常;稍后计划进行另一个增强修复)。<f:ajax>
这仅在当前的 MyFaces 2.2.7 和 PrimeFaces 5.2 版本中不起作用。未来版本可能会提供支持。同时,最好的办法是更新迭代组件本身,或者更新父组件,以防它不呈现 HTML,例如 .<ui:repeat>
使用 PrimeFaces 时,请考虑搜索表达式或选择器
PrimeFaces 搜索表达式允许您通过 JSF 组件树搜索表达式来引用组件。JSF 有几个内置的:
@this
:电流分量@form
:父母UIForm
@all
:整个文档@none
:无
PrimeFaces通过新的关键字和复合表达式支持增强了这一点:
@parent
:父组件@namingcontainer
:父母UINamingContainer
@widgetVar(name)
:由给定的组件标识widgetVar
您还可以在复合表达式中混合这些关键字,例如 、 等。@form:@parent
@this:@parent:@parent
PrimeFaces 选择器 (PFS) 允许您通过 jQuery CSS 选择器语法引用组件。例如,引用在 HTML 输出中具有所有通用样式类的组件。这在您需要引用“大量”组件时特别有用。这仅要求目标组件在 HTML 输出中具有所有客户端 ID(固定或自动生成,无关紧要)。参见 update=“@(.myClass)” 中的 PrimeFaces 选择器如何工作?@(.someclass)
评论
context.getViewRoot().findComponent(":inputform" + UINamingContainer.getSeparatorChar(context) + "inputtext" );
prependId="false"
我知道BalusC已经给出了一个很好的答案,但这里有一个小技巧,我用它来让容器告诉我正确的clientId。
- 删除组件上无法正常工作的更新
- 将具有虚假更新的临时组件放入您尝试更新的组件中
- 点击页面,servlet 异常错误会告诉你需要引用的正确客户端 ID。
- 删除虚假组件并在原始更新中放置正确的 clientId
这是代码示例,因为我的话可能无法最好地描述它。
<p:tabView id="tabs">
<p:tab id="search" title="Search">
<h:form id="insTable">
<p:dataTable id="table" var="lndInstrument" value="#{instrumentBean.instruments}">
<p:column>
<p:commandLink id="select"
删除此组件中失败的更新
oncomplete="dlg.show()">
<f:setPropertyActionListener value="#{lndInstrument}"
target="#{instrumentBean.selectedInstrument}" />
<h:outputText value="#{lndInstrument.name}" />
</p:commandLink>
</p:column>
</p:dataTable>
<p:dialog id="dlg" modal="true" widgetVar="dlg">
<h:panelGrid id="display">
在尝试使用将失败的更新进行更新的 ID 的组件中添加一个组件
<p:commandButton id="BogusButton" update="BogusUpdate"></p:commandButton>
<h:outputText value="Name:" />
<h:outputText value="#{instrumentBean.selectedInstrument.name}" />
</h:panelGrid>
</p:dialog>
</h:form>
</p:tab>
</p:tabView>
点击此页面并查看错误。 错误是: javax.servlet.ServletException:找不到从 tabs:insTable 引用的表达式“BogusUpdate”的组件:BogusButton: BogusButton
因此,要使用的正确 clientId 将是粗体加上目标容器的 id(在本例中显示)
tabs:insTable:display
请注意,从 PrimeFaces 10 及更高版本开始,您可以使用观察者和事件。
这允许您根据关键字设置的自定义事件名称更新组件。例如:@obs(event)
<p:commandButton update="@obs(myEvent)"/>
<h:panelGroup>
<p:autoUpdate on="myEvent"/>
</h:panelGroup>
看:
评论