【问题标题】:How to update button inside <ui: repeat>?如何更新<ui:repeat>中的按钮?
【发布时间】:2021-07-04 21:50:51
【问题描述】:

这是我的问题。我在&lt;ui: repeat&gt; 中有两个&lt;p: commandLink&gt;。 当我单击它们时,我需要通过模拟复选框来更新这些按钮。 在&lt;ui:repeat&gt; 周围更新&lt;panelGroup&gt; 有效。但是,对于包含许多项目的列表,单击更新按钮后,它会使屏幕返回列表顶部,从而无法选择许多项目。有什么方法可以在&lt;p:commandLink&gt; 中提供更新特定行吗?

<tbody>
    <ui:repeat value="#{myBean.itens}" var="item" varStatus="index">
        <tr class="myCustomClass" id="item#{item.id}">
            <th>
                <p:commandLink
                    rendered="#{myConditionRendered}"
                    actionListener="#{myBean.deselect(item)}"
                    update=":panelGroupArroundId"
                    process="@this">
                    <i style="font-size: 15px;" class="fa fa-check-square-o" />
                </p:commandLink>
                <p:commandLink
                    rendered="#{!myConditionRendered}"
                    actionListener="#{myBean.select(item)}"
                    update=":panelGroupArroundId"
                    process="@this">
                    <i style="font-size: 15px;" class="fa fa-square-o" />
                </p:commandLink>
            </th>
            <td>
                <h:outputText value="#{item.field1}"/>
            </td>
            ...                                                         
        </tr>
    </ui:repeat>
</tbody>

JSF 版本:2.1
Primefaces 版本:3.5

【问题讨论】:

    标签: jsf primefaces jsf-2


    【解决方案1】:

    这里的技巧是只更新您需要的部分 - 如果您更新整个容器,浏览器将从最近更新发生的位置重置和刷新。在 JSF 中,有几种方法可以完成您所需要的。更新的 JSF 版本(特别是 2.3)具有可用的选择器,例如 :parent,以便更轻松地针对页面的特定部分进行更新。使用 2.1 时,您会受到一些限制。

    我做了一个快速测试,并提出了一个适用于您的特定用户案例的工作示例。下图使用的是 Font Awesome 和 PrimeFaces 3.5;

    我稍微调整了您的代码并制作了一个完整且有效的示例。在此示例中,控制器和支持 bean 已分离到单独的类中。首先让我们看一下backing bean:

    @Data @Named @ViewScoped
    public class MyBean implements Serializable {
        @Data @RequiredArgsConstructor
        public static class Item {
            @NonNull private String name;
            private boolean selected;
        }
    
        private List<Item> items;
    
        @PostConstruct
        private void init() {
            items = List.of(new Item("a"), new Item("b"), new Item("c"),
                new Item("d"), new Item("e"), new Item("f"), new Item("g"), 
                new Item("h"), new Item("i"), new Item("j")
            );
        }
    }
    

    这定义了我们的数据集并使用 Lombok 来最小化样板代码的数量(@Data@RequiredArgsConstructor)。我还添加了一个 selected 标志来跟踪复选框是否被选中。然后在选择和取消选择时在控制器 bean 中使用它:

    @Data @Named @RequestScoped
    public class MyBeanController {
        @Inject
        private MyBean myBean;
    
        public void select(Item item) {
            item.setSelected(true);
        }
    
        public void deselect(Item item) {
            item.setSelected(false);
        }
    }
    

    此外,这里是视图 (XHTML) 定义:

    <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
          xmlns:p="http://primefaces.org/ui">
        <h:head>
            <title>Button update in UI repeat example</title>
            <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.0.0/css/font-awesome.css" />
        </h:head>
        <h:body>
            <table>
                <tbody>
                    <ui:repeat value="#{myBean.items}" var="item">
                        <tr style="float: left; padding-right: 10px">
                            <th>
                                <h:form>
                                    <h:panelGroup id="content">
                                        <p:commandLink rendered="#{item.selected}"
                                            actionListener="#{myBeanController.deselect(item)}"
                                            update="content" process="@this">
                                            <i class="fa fa-check-square-o" />
                                        </p:commandLink>
                                        <p:commandLink rendered="#{!item.selected}"
                                            actionListener="#{myBeanController.select(item)}"
                                            update="content" process="@this">
                                            <i class="fa fa-square-o" />
                                        </p:commandLink>
                                    </h:panelGroup>
                                </h:form>
                            </th>
                            <td><h:outputText value="#{item.name}"/></td>                                                       
                        </tr>
                    </ui:repeat>
                </tbody>
            </table>
        </h:body>
    </html>
    

    如您所见,我们将按钮包装在表单中并定义了一个容器content,我们在p:commandLink 标记的update 属性中引用该容器。因为我们被包裹在一个表单中,所以 panelGroup 的实际 id 实际上变成了类似于 j_idt6:9:j_idt8:content 的东西,每个 content id 都是唯一的(因为每个表单都有一个唯一的 id 生成)。

    这使我们可以专门定位和更新该行的数据。

    理论上,您可以直接update 表单,而无需将其包装在content 中。但是,当包裹在ui:repeat 中时,这样做会干扰表单的生命周期和处理。添加一个额外的panelGroup 并更新它,就像在这个例子中一样,解决了这个问题。

    【讨论】:

    • 感谢亚当的回答,我已经被这个问题困扰了几天。对我来说,它工作得很好,让我更好地理解了这种行为。我希望你能帮助别人。再次感谢,对不起我的英语。
    • 很高兴听到它有帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 2021-04-22
    • 1970-01-01
    • 2015-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多