简体   繁体   English

如何在循环命名容器内寻址组件

[英]How to address a component inside a looping naming container

I have the following structure (contents and attributes omitted):我有以下结构(内容和属性省略):

<ui:repeat id="outerlist">
    <my:compositeComponent id="myCC">
        <h:panelgroup id="container">
            Some content here (outputText, etc.)
            <ui:repeat id="innerlist">
               <h:commandButton>
                   <f:ajax render=":#{cc.clientId}:container" />

<!-- all closing tags accordingly -->

As the content inside the container depends on the action of the innerlist's button, I need to update it.由于容器内的内容取决于内部列表按钮的操作,因此我需要对其进行更新。 The approach as shown above works, when there is no outer ui:repeat .当没有外部ui:repeat时,如上所示的方法有效。 However, it fails with a component not found error when there is one.但是,当存在component not found错误时,它会失败。

This is seems due to the fact that the cc.clientId then itself contains the row index of the outer ui:repeat , eg outerlist:0:myCC:container .这似乎是由于cc.clientId本身包含外部ui:repeat的行索引,例如outerlist:0:myCC:container As a comment to this answer indicates, this indexed ID is not available in the server-side representation of the view tree.正如对此答案的评论所示,此索引 ID 在视图树的服务器端表示中不可用。 Instead "the row index only exist at client side".相反,“行索引仅存在于客户端”。 I must admit I do not quite understand how this indexing is done and what is available at the server side.我必须承认我不太明白这个索引是如何完成的以及服务器端有什么可用的。

So my question is: How does JSF do this indexing, how does it (on the server) separate different "instances" inside a ui:repeat and is there a solution for what I am trying to achieve with the above code?所以我的问题是:JSF 如何做这个索引,它(在服务器上)如何在ui:repeat分离不同的“实例”,是否有解决方案可以解决我试图用上面的代码实现的目标?

The client ID as specified in <f:ajax> must be available in both the server side by JSF's <f:ajax>指定的客户端 ID 必须在 JSF 的服务器端可用

facesContext.getViewRoot().findComponent(clientId);

(so that it could be found in order to render its new HTML representation for the ajax response) (以便可以找到它以便为 ajax 响应呈现其新的 HTML 表示)

and in the client side by JavaScript's在客户端通过 JavaScript 的

document.getElementById(clientId);

(so that it could be updated/replaced by JS once the ajax response with new HTML content has arrived) (这样一旦带有新 HTML 内容的 ajax 响应到达,它就可以被 JS 更新/替换)

As the <ui:repeat> runs during view render time only, the client ID with the row index does not represent a valid component in server side ("Cannot find component..." error from findComponent() ), but it does represent a valid HTML element in the client side.由于<ui:repeat>仅在视图渲染时间运行,具有行索引的客户端 ID 不代表服务器端的有效组件(来自findComponent() “无法找到组件...”错误),但它确实代表客户端中的有效 HTML 元素。 Basically, you'd need the client ID without the row index for the server side and the one with the row index for the client side.基本上,您需要服务器端没有行索引的客户端 ID 和客户端有行索引的客户端 ID。 But that just won't work for <ui:repeat> as it's (unfortunately) not possible to select the component tree state of a specific iteration round by alone findComponent() .但这对<ui:repeat>不起作用,因为(不幸的是)不可能单独通过findComponent()选择特定迭代轮的组件树状态。

It should work fine when using JSTL <c:forEach> and dynamically assigning component ID as it runs during view build time and also actually generates multiple fullworthy JSF components in the view tree instead of only one which is re-used multiple times during render.当使用 JSTL <c:forEach>并动态分配组件 ID 时,它应该可以正常工作,因为它在视图构建期间运行,并且还在视图树中实际生成多个完整的 JSF 组件,而不是仅在渲染期间多次重用的一个组件。

<c:forEach varStatus="loop">
    <my:compositeComponent id="myCC">
        <h:panelGroup id="container_#{loop.index}">
            Some content here (outputText, etc.)
            <ui:repeat id="innerlist_#{loop.index}">
               <h:commandButton>
                   <f:ajax render=":#{cc.clientId}:container_#{loop.index}" />

This has however its own implications, certainly when used with composite components and also when used in nested loops.然而,这有其自身的含义,当然当与复合组件一起使用时以及在嵌套循环中使用时。 Your code is not complete enough to give insight and advice about that.您的代码不够完整,无法就此提供见解和建议。 It would for example break when this piece of code is placed in a composite component which is by itself also reused multiple times in a render time loop.例如,当这段代码被放置在一个复合组件中时,它会中断,该组件本身也在渲染时间循环中多次重用。

See also:也可以看看:

As an update: In this particular case, using c:foreach was not an option, as both lists need to be dynamic (although this route saved me a lot of trouble in some other cases) Instead I added an attribute to the composite component to pass an optional "update scope" like so:作为更新:在这种特殊情况下,使用c:foreach不是一个选项,因为两个列表都需要是动态的(尽管这条路线在其他一些情况下为我省去了很多麻烦)相反,我向复合组件添加了一个属性传递一个可选的“更新范围”,如下所示:

<cc:attribute name="updateScope" required="false" type="java.lang.String"  
              default=":#{cc.clientId}:container" />

By setting a default, I do not need to alter any uses of the components in a non-looping context.通过设置默认值,我不需要在非循环上下文中更改组件的任何使用。 However, if I want to use it inside a ui:repeat I can pass an ID to the attribute that is wide enough to enclose the outer loop.但是,如果我想在ui:repeat使用它,我可以将 ID 传递给足够宽以包含外部循环的属性。 Often, this would be an h:panelGroup id="wrapper" just around the ui:repeat .通常,这将是ui:repeat周围的h:panelGroup id="wrapper"

Obviously, this has quite some drawbacks: it updates all children of the loop, which could possibly result in a lot of unnecessary content being re-rendered.显然,这有很多缺点:它更新循环的所有子级,这可能会导致重新渲染大量不必要的内容。 One nasty side-effect of this is that error messages and local values of these siblings are reset.一个令人讨厌的副作用是这些兄弟的错误消息和本地值被重置。 In one of our pages it additionally causes all expanded panels to be reset into closed state.在我们的其中一个页面中,它还会导致所有展开的面板重置为关闭状态。

However, if these problems are of no importance (for example: my original example referred to a component that has no input fields or panels, but only feedback text and the action), the additional attribute can be a simple approach to work around the described issue.但是,如果这些问题并不重要(例如:我的原始示例引用的组件没有输入字段或面板,而只有反馈文本和操作),则附加属性可以是解决所描述的问题的简单方法问题。

我只是自己解决了这个问题:

update=":#{cc.clientId.replaceAll(':[0-9]+:', ':')}"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM