jsf如何找到ajax更新/呈现组件的客户端ID?找不到从“bar”引用的表达式为“foo”的组件
下面的代码受PrimeFaces DataGrid+DataTable教程的启发,并放入位于<p:layout>
的<p:layoutUnit>
中的<p:tab>
的<p:tabView>
中。下面是代码的内部部分(从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>
时,代码停止工作,并给出message:
Cannot find component with expression "insTable:display" referenced from "tabs:insTable:select".
当我使用<f:ajax>
尝试相同的方法时,它失败了,不同的message基本上告诉了我相同的信息:
<f:ajax>
contains an unknown id "insTable:display" cannot locate it in the context of the component "tabs:insTable:select"
当它发生在另一个Ajax回发期间,并且JSF项目阶段设置为Development
,那么它将失败,并发出带有message的JavaScript警报:
malformedXML: During update: insTable:display not found
这是如何造成的,我如何解决
# 1 楼答案
在HTML输出中查找实际的客户端ID
您需要查看生成的HTML输出以找到正确的客户端ID。在浏览器中打开页面,右键单击并查看源代码。找到感兴趣的JSF组件的HTML表示,并将其
id
作为客户端ID。根据当前命名容器的不同,您可以以绝对或相对方式使用它。见下一章注意:如果它恰好包含
:0:
、:1:
等迭代索引(因为它位于迭代组件内部),那么您需要意识到并不总是支持更新特定的迭代轮。关于这方面的更多细节,请参见答案的底部记住
NamingContainer
组件并始终给它们一个固定的ID如果您希望通过ajax进程/execute/update/render引用的组件位于同一个^{} 父级中,那么只需引用它自己的ID即可
如果它不在同一个
NamingContainer
内,则需要使用绝对客户端ID引用它。绝对客户端ID以NamingContainer
分隔符开头,默认情况下为:
^{} 组件是例如} 可能会在这方面有所帮助
<h:form>
、<h:dataTable>
、<p:tabView>
、<cc:implementation>
(因此,所有复合组件)等。通过查看生成的HTML输出,您可以很容易地识别它们,它们的ID将放在所有子组件的生成的客户端ID之前。注意,当它们没有固定ID时,JSF将使用自动生成的j_idXXX
格式的ID。您应该通过给他们一个固定的ID来避免这种情况。在开发过程中,OmniFaces ^{如果您知道如何找到所讨论的} 接口。例如,^{} (在} (在
UIComponent
的javadoc,那么您也可以在那里检查它是否实现了^{<h:form>
后面的UIComponent
标记)显示它实现了NamingContainer
,但是^{UIComponent
后面的<h:panelGroup>
标记)没有显示它,因此它没有实现NamingContainer
Here is the javadoc of all standard components和here is the javadoc of PrimeFaces解决您的问题
因此,在您的案例中:
生成的
<h:panelGrid id="display">
HTML输出如下所示:您需要准确地将
id
作为客户端ID,然后在update
中使用:
作为前缀:引用外部include/tagfile/composite
如果此命令链接位于include/tagfile内部,而目标位于该文件外部,因此您不一定知道当前命名容器的命名容器父级的ID,那么您可以通过
UIComponent#getNamingContainer()
动态引用它,如下所示:或者,如果此命令链接位于复合构件内部,而目标位于复合构件外部:
或者,如果命令链接和目标都位于同一复合组件内:
另见Get id of parent naming container in template for in render / update attribute
它是如何在封面下工作的
这一切都在the ^{} javadoc 中指定为“搜索表达式”:
注意,PrimeFaces也遵循JSF规范,但是RichFaces使用"some additional exceptions"
这些额外的异常没有详细描述,但众所周知,相对组件ID(即不以
:
开头的组件ID)不仅在最近的父组件NamingContainer
的上下文中搜索,而且在同一视图中的所有其他NamingContainer
组件中搜索(顺便说一句,这是一项相对昂贵的工作)切勿使用
prependId="false"
如果这一切仍然不起作用,那么请验证您是否没有使用
<h:form prependId="false">
。这将在处理ajax提交和渲染过程中失败。另见这一相关问题:UIForm with prependId="false" breaks <f:ajax render>引用迭代组件的特定迭代轮
在很长一段时间内,在诸如
<ui:repeat>
和<h:dataTable>
之类的迭代组件中无法引用特定的迭代项,如下所示:但是,由于Mojarra 2.2.5
<f:ajax>
开始支持它(它只是停止验证它;因此永远不要再面对上述问题中的例外;计划稍后对此进行另一个增强修复)这仅在当前MyFaces 2.2.7和PrimeFaces 5.2版本中不起作用。这种支持可能会出现在未来的版本中。同时,最好的办法是更新迭代组件本身,或者更新父组件,以防它不呈现HTML,如
<ui:repeat>
使用PrimeFras时,考虑搜索表达式或选择器< EH3>
PrimeFaces Search Expressions允许您通过JSF组件树搜索表达式引用组件。JSF有几个内置组件:
@this
:当前组件@form
:父UIForm
@all
:整个文档@none
:什么都没有PrimeFaces通过新的关键字和复合表达式支持对此进行了增强:
@parent
:父组件@namingcontainer
:父UINamingContainer
@widgetVar(name)
:由给定的{您还可以在复合表达式中混合这些关键字,例如
@form:@parent
、@this:@parent:@parent
等@(.someclass)
中的PrimeFaces Selectors (PFS)允许您通过jQuery CSS选择器语法引用组件。例如,在HTML输出中引用具有所有公共样式类的组件。当您需要引用“很多”组件时,这尤其有用。这只要求目标组件在HTML输出中具有所有客户端ID(固定或自动生成,无所谓)。另见How do PrimeFaces Selectors as in update="@(.myClass)" work?# 2 楼答案
首先:据我所知,在选项卡视图中放置对话框是一种不好的做法。。。你最好把它拿出来
现在谈谈你的问题:
对不起,我花了一些时间才得到你想要实现的东西
刚才我自己在我的网络应用上做了,而且很有效
正如我之前所说的,将p:对话框放在'p:tabView'的外侧
按照最初的建议保留p:对话框:
p:commandlink应该是这样的(我所做的只是更改update属性)
这同样适用于我的web应用程序,如果它不适用于您,那么我猜您的JavaBean代码中有错误
# 3 楼答案
尝试将
update="insTable:display"
更改为update="display"
。我相信你不能像那样在id前面加上表单id# 4 楼答案
这是因为选项卡也是一个命名容器。。。您的更新应该是
update="Search:insTable:display"
。您也可以做的是将对话框放在表单外部,仍然放在选项卡内部,然后它将是:update="Search:display"
# 5 楼答案
我知道BalusC已经给出了一个很好的答案,但是这里有一个小技巧,我可以让容器告诉我正确的clientId
这里是代码示例,因为我的话可能无法最好地描述它
删除此组件中失败的更新
使用将失败的更新在您尝试更新的id的组件中添加组件
点击此页面并查看错误。 错误是: javax。servlet。ServletException:找不到引用自的表达式“BoguUpdate”的组件 选项卡:不稳定:BogusButton
因此,要使用的正确clientId将是粗体加上目标容器的id(在本例中显示)