如何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 。 然后,将调用此NamingContainerfindComponent()方法,传递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前缀。