如何findajax更新/渲染组件的客户端ID? 无法find含有“bar”引用的expression式“foo”的组件
以下代码受PrimeFaces DataGrid + DataTable教程的启发,并放置在驻留在<p:layoutUnit>
的<p:tabView>
中的<p:layoutUnit>
的<p:layoutUnit>
中。 这里是代码的内部部分(从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”引用的expression式“insTable:display”找不到组件。
当我使用<f:ajax>
进行相同的尝试时,它会失败,并显示一条基本上不同的消息:
<f:ajax>
包含一个未知的id“insTable:display”在组件的上下文中找不到它“选项卡:insTable:select”
这是如何造成的,我该如何解决?
在HTML输出中查找实际的客户端ID
您需要查看生成的HTML输出以找出正确的客户端ID。 在浏览器中打开页面,右键单击并查看源代码 。 find感兴趣的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
在开发过程中可能会有所帮助。
如果你知道要findUIComponent
的javadoc,那么你也可以在那里检查它是否实现了NamingContainer
接口。 例如, HtmlForm
( <h:form>
标签后面的UIComponent
)显示它实现了NamingContainer
,但是HtmlPanelGroup
( <h:panelGroup>
标签后面的UIComponent
)没有显示它,所以它没有实现NamingContainer
。 这里是所有标准组件 的javadoc,这里是PrimeFaces的javadoc 。
解决你的问题
所以在你的情况下:
<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 / 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">
在render / update属性中,另请参见获取模板中父命名容器的标识
它是如何工作的
这一切在UIComponent#findComponent()
javadoc中被指定为“searchexpression式” :
searchexpression式由一个标识符(与
UIComponent
的id属性完全匹配,或由UINamingContainer#getSeparatorChar
字符值链接的一系列这样的标识符组成)。searchalgorithm应该如下操作,尽pipe可以使用替代的algorithm只要最终的结果是一样的:
- 通过在满足以下条件之一时立即停止,确定将作为search基础的
UIComponent
:
- 如果searchexpression式以分隔符(称为“绝对”searchexpression式)开始,则基数将是组件树的根
UIComponent
。 前面的分隔符将被剥离,searchexpression式的其余部分将被视为“相对”searchexpression式,如下所述。- 否则,如果这个
UIComponent
是一个NamingContainer
,它将作为基础。- 否则,search这个组件的父母。 如果遇到
NamingContainer
,它将成为基础。- 否则(如果没有遇到
NamingContainer
),根UIComponent
将成为基础。- searchexpression式(可能在前一步骤中修改)现在是一个“相对”searchexpression式,将用于在基本组件的范围内定位具有匹配的id的组件(如果有的话)。 比赛进行如下:
- 如果searchexpression式是一个简单的标识符,则将该值与id属性进行比较,然后recursion地通过基本
UIComponent
的构面和子元素(除非如果findNamingContainer
的后代,则不search其自己的构面和子项)。- 如果searchexpression式包含多个由分隔符分隔的标识符,则使用第一个标识符按照前一个项目符号点中的规则定位
NamingContainer
。 然后,将调用此NamingContainer
的findComponent()
方法,传递searchexpression式的其余部分。
请注意,PrimeFaces也遵守JSF规范,但是RichFaces使用“一些额外的例外” 。
“reRender”使用
UIComponent.findComponent()
algorithm(还有一些例外)来查找组件树中的组件。
这些附加的例外情况没有详细描述,但是已知相关组件ID(即不是以……开始的)不仅在最接近的父NamingContainer
的上下文中search,而且在相同视图中的所有其他NamingContainer
组件中search是一个相对昂贵的工作方式)。
切勿使用prependId="false"
如果这一切仍然不起作用,那么validation您是否使用<h:form prependId="false">
。 这将在处理ajax提交和呈现过程中失败。 另请参阅以下相关问题: 带有prependId =“false”的UIForm会中断<f:ajax render> 。
引用迭代组件的特定迭代轮
很久没有可能在像<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开始支持它(它只是停止validation它,因此你将永远不会面临在提到的例外问题;另一个增强的修补程序计划在以后)。
这只在当前的MyFaces 2.2.7和PrimeFaces 5.2版本中不起作用。 支持可能会在未来的版本。 与此同时,最好的办法是更新迭代组件本身,或者更新父项,以防止它不呈现HTML,如<ui:repeat>
。
使用PrimeFaces时,请考虑searchexpression式或select器
PrimeFacessearchexpression式允许您通过JSF组件树searchexpression式来引用组件。 JSF有几个内build的:
-
@this
:当前组件 -
UIForm
:父UIForm
-
@all
:整个文件 -
@none
:什么都没有
PrimeFaces使用新的关键字和复合expression式支持增强了这一点:
-
@parent
:父组件 -
@namingcontainer
:父级UINamingContainer
-
@widgetVar(name)
:由给定的widgetVar
标识的widgetVar
您还可以在复合expression式中混合这些关键字,例如@this:@parent:@parent
@form:@parent
, @form:@parent
@this:@parent:@parent
等
像@(.someclass)
PrimeFacesselect器(PFS)允许您通过jQuery CSSselect器语法来引用组件。 例如,在HTML输出中引用具有所有常见样式类的组件。 如果您需要引用“很多”组件,这特别有用。 这只要求目标组件在HTML输出中具有所有客户端ID(固定或自动生成,无关紧要)。 另请参见PrimeFacesselect器如何在update =“@(。myClass)”中工作?
首先:据我所知在TabView中放置对话是一个不好的做法…你最好把它拿出来…
现在回答你的问题:
对不起,花了我一些时间来得到你想要实现的东西,
我刚刚在自己的networking应用程序中做了一些工作
正如我之前所说的将p:对话框放在`p:tabView,
按照最初的build议离开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>
在我的networking应用程序相同的作品,如果它不适合你,那么我想你的Java bean代码有什么问题…
这是因为该选项卡是一个命名容器以及…你的更新应该是update="Search:insTable:display"
你可以做的也只是把你的对话框的forms,仍然在标签内,那么它将是: update="Search:display"
尝试update="insTable:display"
update="display"
。 我相信你不能用这样的ID作为ID前缀。