如何找出ajax更新/渲染组件的客户端ID?找不到带有表达式“foo"的组件引用自“bar" [英] How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"

查看:15
本文介绍了如何找出ajax更新/渲染组件的客户端ID?找不到带有表达式“foo"的组件引用自“bar"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码的灵感来自 PrimeFaces DataGrid + DataTable Tutorials 并放入 的代码>.这是代码的内部部分(从 p:tab 组件开始);外部是微不足道的.

The following code is inspired from PrimeFaces DataGrid + DataTable Tutorials and put into a <p:tab> of a <p:tabView> residing in a <p:layoutUnit> of a <p:layout>. Here is the inner part of the code (starting from p:tab component); the outer part is trivial.

<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>

当我单击 时,代码停止工作并显示 消息:

When I click the <p:commandLink>, the code stops working and gives the message:

无法找到带有表达式insTable:display"的组件;引用自tabs:insTable:select".

Cannot find component with expression "insTable:display" referenced from "tabs:insTable:select".

当我使用 <f:ajax> 尝试相同的操作时,它会失败并显示不同的 message 基本上是一样的:

When I try the same using <f:ajax>, then it fails with a different message basically telling the same:

包含未知 IDinsTable:display";无法在组件tabs:insTable:select"的上下文中找到它

<f:ajax> contains an unknown id "insTable:display" cannot locate it in the context of the component "tabs:insTable:select"

当它在另一个 Ajax 回发期间发生并且 JSF 项目阶段设置为 Development 时,它会失败并显示 消息:

When it happens during another Ajax postback and the JSF project stage is set to Development, then it fails with a JavaScript alert with the message:

malformedXML:更新期间:insTable:display not found

malformedXML: During update: insTable:display not found

这是怎么引起的,我该如何解决?

How is this caused and how can I solve it?

推荐答案

在 HTML 输出中查找实际客户端 ID

您需要查看生成的 HTML 输出以找出正确的客户端 ID.在浏览器中打开页面,右键单击并查看源代码.找到感兴趣的 JSF 组件的 HTML 表示并将其 id 作为客户端 ID.您可以根据当前命名容器以绝对或相对方式使用它.请参阅以下章节.

Look in HTML output for actual client ID

You need to look in the generated HTML output to find out the right client ID. Open the page in browser, do a rightclick and View Source. Locate the HTML representation of the JSF component of interest and take its id as client ID. You can use it in an absolute or relative way depending on the current naming container. See following chapter.

注意:如果它碰巧包含:0::1:等迭代索引(因为它在迭代组件内),那么你需要意识到并不总是支持更新特定的迭代轮次.有关详细信息,请参阅答案底部.

Note: if it happens to contain iteration index like :0:, :1:, etc (because it's inside an iterating component), then you need to realize that updating a specific iteration round is not always supported. See bottom of answer for more detail on that.

如果您想通过 ajax process/execute/update/render 引用的组件位于同一个 NamingContainer 父级,然后只引用它自己的 ID.

If a component which you'd like to reference by ajax process/execute/update/render is inside the same NamingContainer parent, then just reference its own ID.

<h:form id="form">
    <p:commandLink update="result"> <!-- OK! -->
    <h:panelGroup id="result" />
</h:form>

如果它不在在同一个 NamingContainer 中,那么您需要使用绝对客户端 ID 来引用它.绝对客户端 ID 以 NamingContainer 分隔符开头,默认情况下为 :.

If it's not inside the same NamingContainer, then you need to reference it using an absolute client ID. An absolute client ID starts with the NamingContainer separator character, which is by default :.

<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 组件例如 <cc:implementation>(因此,所有复合组件)等.您可以通过查看生成的 HTML 输出轻松识别它们,它们的 ID 将附加到所有子组件的生成客户端 ID.请注意,当它们没有固定 ID 时,JSF 将使用 j_idXXX 格式的自动生成的 ID.您应该通过给他们一个固定的 ID 来绝对避免这种情况.OmniFaces NoAutoGeneratedIdViewHandler 可能在开发过程中对此有所帮助.

NamingContainer components are for example <h:form>, <h:dataTable>, <p:tabView>, <cc:implementation> (thus, all composite components), etc. You recognize them easily by looking at the generated HTML output, their ID will be prepended to the generated client ID of all child components. Note that when they don't have a fixed ID, then JSF will use an autogenerated ID in j_idXXX format. You should absolutely avoid that by giving them a fixed ID. The OmniFaces NoAutoGeneratedIdViewHandler may be helpful in this during development.

如果您知道要找到有问题的 UIComponent 的 javadoc,那么您也可以在那里检查它是否实现了 NamingContainer 接口与否.例如,HtmlForm( 标签后面的UIComponent)显示它实现了NamingContainer,但是HtmlPanelGroup( 标签后面的>UIComponent 没有显示出来,所以它没有实现NamingContainer.这里是所有标准组件的javadoc这里是 PrimeFaces 的 javadoc.

If you know to find the javadoc of the UIComponent in question, then you can also just check in there whether it implements the NamingContainer interface or not. For example, the HtmlForm (the UIComponent behind <h:form> tag) shows it implements NamingContainer, but the HtmlPanelGroup (the UIComponent behind <h:panelGroup> tag) does not show it, so it does not implement NamingContainer. Here is the javadoc of all standard components and 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">

生成的 HTML 输出如下所示:

The generated HTML output of <h:panelGrid id="display"> looks like this:

<table id="tabs:insTable:display">

您需要准确地将该 id 作为客户端 ID,然后在 update:

You need to take exactly that id as client ID and then prefix with : for usage in update:

<p:commandLink update=":tabs:insTable:display">

在 include/tagfile/composite 之外引用

如果这个命令链接在一个include/tagfile里面,而目标在它外面,因此你不一定知道当前命名容器的命名容器父级的ID,那么你可以通过<动态引用它代码>UIComponent#getNamingContainer() 像这样:

<p:commandLink update=":#{component.namingContainer.parent.namingContainer.clientId}:display">

或者,如果此命令链接在复合组件内部而目标在其外部:

Or, if this command link is inside a composite component and the target is outside it:

<p:commandLink update=":#{cc.parent.namingContainer.clientId}:display">

或者,如果命令链接和目标都在同一个复合组件中:

Or, if both the command link and target are inside same composite component:

<p:commandLink update=":#{cc.clientId}:display">

另见获取模板中父命名容器的 id 以用于渲染/更新属性

这一切都在 #findComponent-java.lang.String-" rel="noreferrer">UIComponent#findComponent() javadoc:

This all is specified as "search expression" in the UIComponent#findComponent() javadoc:

搜索表达式由一个标识符(与 UIComponent 的 id 属性完全匹配,或者由 链接的一系列此类标识符组成)UINamingContainer#getSeparatorChar 字符值.搜索算法应如下操作,但可以使用替代算法,只要最终结果相同即可:

A search expression consists of either an identifier (which is matched exactly against the id property of a UIComponent, or a series of such identifiers linked by the UINamingContainer#getSeparatorChar character value. The search algorithm should operates as follows, though alternate alogrithms may be used as long as the end result is the same:

  • 通过在满足以下条件之一时立即停止来识别将作为搜索基础的 UIComponent:
    • 如果搜索表达式以分隔符开头(称为绝对"搜索表达式),则基础将是组件树的根 UIComponent.前导分隔符将被去除,搜索表达式的其余部分将被视为相对"搜索表达式,如下所述.
    • 否则,如果这个 UIComponent 是一个 NamingContainer,它将作为基础.
    • 否则,搜索此组件的父级.如果遇到 NamingContainer,它将成为基础.
    • 否则(如果没有遇到NamingContainer)根UIComponent 将是基础.
    • Identify the UIComponent that will be the base for searching, by stopping as soon as one of the following conditions is met:
      • If the search expression begins with the the separator character (called an "absolute" search expression), the base will be the root UIComponent of the component tree. The leading separator character will be stripped off, and the remainder of the search expression will be treated as a "relative" search expression as described below.
      • Otherwise, if this UIComponent is a NamingContainer it will serve as the basis.
      • Otherwise, search up the parents of this component. If a NamingContainer is encountered, it will be the base.
      • Otherwise (if no NamingContainer is encountered) the root UIComponent will be the base.
      • 如果搜索表达式是一个简单的标识符,则将此值与 id 属性进行比较,然后递归地遍历基础 UIComponent 的构面和子项(除非是后代 NamingContainer 被找到,它自己的方面和孩子不被搜索).
      • 如果搜索表达式包含多个由分隔符分隔的标识符,则第一个标识符用于根据上一个要点中的规则定位 NamingContainer.然后,将调用此 NamingContainerfindComponent() 方法,传递搜索表达式的其余部分.
      • If the search expression is a simple identifier, this value is compared to the id property, and then recursively through the facets and children of the base UIComponent (except that if a descendant NamingContainer is found, its own facets and children are not searched).
      • If the search expression includes more than one identifier separated by the separator character, the first identifier is used to locate a NamingContainer by the rules in the previous bullet point. Then, the findComponent() method of this NamingContainer will be called, passing the remainder of the search expression.

      请注意,PrimeFaces 也遵循 JSF 规范,但 RichFaces 使用 一些额外的例外".

      Note that PrimeFaces also adheres the JSF spec, but RichFaces uses "some additional exceptions".

      "reRender" 使用 UIComponent.findComponent() 算法(有一些额外的例外)在组件树中查找组件.

      "reRender" uses UIComponent.findComponent() algorithm (with some additional exceptions) to find the component in the component tree.

      这些额外的异常没有详细描述,但众所周知,相关组件 ID(即那些不以 : 开头的)不仅在最近的父 NamingContainer<的上下文中搜索/code>,但也包含在同一视图中的所有其他 NamingContainer 组件中(顺便说一下,这是一项相对昂贵的工作).

      Those additional exceptions are nowhere in detail described, but it's known that relative component IDs (i.e. those not starting with :) are not only searched in the context of the closest parent NamingContainer, but also in all other NamingContainer components in the same view (which is a relatively expensive job by the way).

      如果这一切仍然不起作用,请验证您是否没有使用 <h:form prependId="false">.这将在处理 ajax 提交和渲染期间失败.另请参阅此相关问题:UIForm with prependId="false";中断 .

      If this all still doesn't work, then verify if you aren't using <h:form prependId="false">. This will fail during processing the ajax submit and render. See also this related question: UIForm with prependId="false" breaks <f:ajax render>.

      很长一段时间内都无法在诸如 之类的迭代组件中引用特定的迭代项,如下所示:

      It was for long time not possible to reference a specific iterated item in iterating components like <ui:repeat> and <h:dataTable> like so:

      <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> 开始支持它(它只是停止验证它;因此你将永远不会再遇到问题中提到的异常;另一个增强计划稍后修复).

      However, since Mojarra 2.2.5 the <f:ajax> started to support it (it simply stopped validating it; thus you would never face the in the question mentioned exception anymore; another enhancement fix is planned for that later).

      这仅在当前的 MyFaces 2.2.7 和 PrimeFaces 5.2 版本中不起作用.将来的版本中可能会提供支持.同时,最好的办法是更新迭代组件本身,或者更新父组件,以防它不呈现 HTML,例如 .

      This only doesn't work yet in current MyFaces 2.2.7 and PrimeFaces 5.2 versions. The support might come in the future versions. In the meanwhile, your best bet is to update the iterating component itself, or a parent in case it doesn't render HTML, like <ui:repeat>.

      PrimeFaces Search Expressions 允许您通过 JSF 组件树引用组件搜索表达式.JSF 有几个内置:

      PrimeFaces Search Expressions allows you to reference components via JSF component tree search expressions. JSF has several builtin:

      • @this:当前组件
      • @form:父UIForm
      • @all:整个文档
      • @none:没有
      • @this: current component
      • @form: parent UIForm
      • @all: entire document
      • @none: nothing

      PrimeFaces 通过新的关键字和复合表达式支持增强了这一点:

      PrimeFaces has enhanced this with new keywords and composite expression support:

      • @parent:父组件
      • @namingcontainer:父UINamingContainer
      • @widgetVar(name):由给定的widgetVar
      • 标识的组件
      • @parent: parent component
      • @namingcontainer: parent UINamingContainer
      • @widgetVar(name): component as identified by given widgetVar

      您也可以在复合表达式中混合这些关键字,例如@form:@parent@this:@parent:@parent

      You can also mix those keywords in composite expressions such as @form:@parent, @this:@parent:@parent, etc.

      PrimeFaces 选择器 (PFS)@(.someclass) 允许您通过 jQuery CSS 选择器语法引用组件.例如.引用在 HTML 输出中具有所有公共样式类的组件.这在您需要引用很多"组件的情况下特别有用.这只是预先要求目标组件在 HTML 输出中具有所有客户端 ID(固定或自动生成,无关紧要).另请参阅 如何使用 PrimeFaces Selectors as in update="@(.myClass)"工作吗?

      PrimeFaces Selectors (PFS) as in @(.someclass) allows you to reference components via jQuery CSS selector syntax. E.g. referencing components having all a common style class in the HTML output. This is particularly helpful in case you need to reference "a lot of" components. This only prerequires that the target components have all a client ID in the HTML output (fixed or autogenerated, doesn't matter). See also How do PrimeFaces Selectors as in update="@(.myClass)" work?

      这篇关于如何找出ajax更新/渲染组件的客户端ID?找不到带有表达式“foo"的组件引用自“bar"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆