以下代码的灵感来自PrimeFaces DataGrid + DataTable教程,并放置在<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>
当我点击<f:ajax>
时,代码停止工作并发出消息:
找不到“tabs:insTable:select”引用的表达式为“insTable:display”的组件。
当我使用<f:ajax>
尝试相同的操作时,它会失败并显示基本相同的不同消息:
{{1}}包含一个未知ID“insTable:display”无法在组件“tabs:insTable:select”
的上下文中找到它
这是如何引起的?如何解决?
答案 0 :(得分:284)
您需要查看生成的HTML输出以找出正确的客户端ID。在浏览器中打开页面,右键单击查看源。找到感兴趣的JSF组件的HTML表示形式,并将其id
作为客户端ID。您可以以绝对方式或相对方式使用它,具体取决于当前的命名容器。见下一章。
注意:如果碰巧包含迭代索引,如:0:
,:1:
等(因为它在迭代组件中),那么您需要意识到更新特定的迭代轮次并不总是支持。有关详细信息,请参阅答案底部。
NamingContainer
组件并始终为其提供固定ID 如果您想通过ajax process / execute / update / render引用的组件位于同一个NamingContainer
父级内,那么只需引用自己的ID。
<h:form id="form">
<p:commandLink update="result"> <!-- OK! -->
<h:panelGroup id="result" />
</h:form>
如果它在同一NamingContainer
内不,则需要使用绝对客户端ID引用它。绝对客户端ID以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>
NamingContainer
组件例如是<h:form>
,<h:dataTable>
,<p:tabView>
,<cc:implementation>
(因此,所有复合组件)等。您可以通过以下方式轻松识别它们查看生成的HTML输出,它们的ID将被添加到所有子组件的生成的客户端ID之前。请注意,当他们没有固定ID时,JSF将使用j_idXXX
格式的自动生成ID。你应该通过给他们一个固定的ID来绝对避免这种情况。 OmniFaces NoAutoGeneratedIdViewHandler
在开发过程中可能对此有所帮助。
如果你知道找到有问题的UIComponent
的javadoc,那么你也可以在那里检查它是否实现了NamingContainer
接口。例如,HtmlForm
(UIComponent
标记后面的<h:form>
显示它实现NamingContainer
,但HtmlPanelGroup
(UIComponent
后面<h:panelGroup>
1}} tag)没有显示它,所以它没有实现NamingContainer
。 Here is the javadoc of all standard components和here is the javadoc of PrimeFaces。
所以在你的情况下:
<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">
<h:panelGrid id="display">
生成的HTML输出如下所示:
<table id="tabs:insTable:display">
您需要将id
作为客户ID,然后使用:
作为前缀,以便在update
中使用:
<p:commandLink update=":tabs:insTable:display">
如果此命令链接在include / tagfile中,并且目标在其外部,因此您不必知道当前命名容器的命名容器父ID的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">
另见Get id of parent naming container in template for in render / update attribute
这一切都在the UIComponent#findComponent()
javadoc中指定为&#34;搜索表达式&#34; :
搜索表达式由标识符(与
UIComponent
的id属性完全匹配)或由UINamingContainer#getSeparatorChar
字符链接的一系列此类标识符组成搜索算法的操作如下,尽管可以使用替代算法,只要最终结果相同:
- 通过在满足以下条件之一时立即停止,确定将成为搜索基础的
UIComponent
:
- 如果搜索表达式以分隔符开头(称为&#34;绝对&#34;搜索表达式),则基数将是组件树的根
UIComponent
。将剥离前导分隔符,并将搜索表达式的其余部分视为&#34; relative&#34;搜索表达式如下所述。- 否则,如果此
UIComponent
为NamingContainer
,则以NamingContainer
为基础。- 否则,请搜索此组件的父级。如果遇到
NamingContainer
,它将成为基础。- 否则(如果没有遇到
UIComponent
),根UIComponent
将成为基础。- 搜索表达式(可能在上一步中修改)现在是一个&#34;亲戚&#34;搜索表达式,用于在基本组件的范围内定位具有匹配id的组件(如果有)。比赛按如下方式进行:
- 如果搜索表达式是一个简单的标识符,则将此值与id属性进行比较,然后递归遍历基类
NamingContainer
的facets和子项(除非找到后代NamingContainer
,它自己的方面和孩子都没有被搜查过。)- 如果搜索表达式包含由分隔符分隔的多个标识符,则第一个标识符用于按前一个项目符号点中的规则查找
findComponent()
。然后,将调用此NamingContainer
的{{1}}方法,传递搜索表达式的其余部分。
请注意,PrimeFaces也遵守JSF规范,但RichFaces使用"some additional exceptions"。
&#34; reRender&#34; 使用
UIComponent.findComponent()
算法(除了一些额外的例外)来查找组件树中的组件。
这些额外的例外没有详细描述,但是已知相关组件ID(即不以:
开头的那些)不仅在最近的父{{1}的上下文中搜索},但也在同一视图中的所有其他NamingContainer
组件中(顺便说一句,这是一项相对昂贵的工作)。
NamingContainer
如果这一切仍然不起作用,请验证您是否使用prependId="false"
。在处理ajax提交和呈现期间,这将失败。另请参阅此相关问题:UIForm with prependId="false" breaks <f:ajax render>。
很长一段时间不可能在迭代<h:form prependId="false">
和<ui:repeat>
等组件中引用特定的迭代项目,如下所示:
<h:dataTable>
然而,由于Mojarra 2.2.5 <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>
开始支持它(它只是停止验证它;因此你再也不会面对提到异常的问题了;后来计划另一个增强修复)。
这仅适用于当前的MyFaces 2.2.7和PrimeFaces 5.2版本。未来版本可能会提供支持。同时,最好的办法是更新迭代组件本身,或者更新父组件,以防它不提供HTML,如<f:ajax>
。
PrimeFaces Search Expressions允许您通过JSF组件树搜索表达式引用组件。 JSF有几个内置:
<ui:repeat>
:当前组件@this
:父@form
UIForm
:整篇文档@all
:没有PrimeFaces通过新的关键字和复合表达支持增强了这一点:
@none
:父组件@parent
:父@namingcontainer
UINamingContainer
:由给定@widgetVar(name)
您还可以将这些关键字与widgetVar
,@form:@parent
等复合表达式混合使用。
@this:@parent:@parent
中的PrimeFaces Selectors (PFS)允许您通过jQuery CSS选择器语法引用组件。例如。引用HTML输出中具有所有通用样式类的组件。如果您需要参考&#34;很多&#34;组件。这只是预先确定目标组件在HTML输出中具有所有客户端ID(固定或自动生成,并不重要)。另请参阅How do PrimeFaces Selectors as in update="@(.myClass)" work?
答案 1 :(得分:9)
首先:据我所知,在tabview中放置对话框是一种不好的做法......你最好把它拿出来......
现在问你的问题:
抱歉,花了一些时间来确定你想要实现什么,我刚刚在我的网络应用程序上做了,并且它可以正常工作
正如我之前所说的那样将p:对话框放在`p:tabView,
之外按照您最初的建议离开p:对话框:
<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>
同样适用于我的网络应用程序,如果它不适合你,那么我猜你的java bean代码有问题......
答案 2 :(得分:5)
这是因为标签是一个命名容器以及......你的更新应该是update="Search:insTable:display"
你可以做的只是将你的对话放在表单之外但仍然在标签内然后它是:{{1 }}
答案 3 :(得分:0)
尝试将update="insTable:display"
更改为update="display"
。我相信你不能像这样给表单ID添加id。
答案 4 :(得分:0)
我知道BalusC已经对此做出了很好的回答,但是这里有一个小技巧,我可以使用它来使容器告诉我正确的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:找不到从中引用的表达式“ BogusUpdate”的组件 tabs:insTable: BogusButton
因此,正确使用的clientId将为粗体加目标容器的ID(在这种情况下显示)
tabs:insTable:display