如何更新 <ui: repeat> 内的按钮?
How to update button inside <ui: repeat>?
这是我的问题。我在一个 <ui: repeat>
里面有两个 <p: commandLink>
。
单击它们时,我需要通过模拟复选框来更新这些按钮。
在 <ui:repeat>
附近更新 <panelGroup>
有效。但是,对于包含许多项目的列表,在单击更新按钮后,它会使屏幕返回到列表的顶部,这使得 select 许多项目变得不切实际。有什么方法可以在 <p:commandLink>
中提供更新特定行吗?
<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 中,有几种方法可以完成您的需要。较新版本的 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
并更新它,就像在这个例子中一样,解决了这个问题。
这是我的问题。我在一个 <ui: repeat>
里面有两个 <p: commandLink>
。
单击它们时,我需要通过模拟复选框来更新这些按钮。
在 <ui:repeat>
附近更新 <panelGroup>
有效。但是,对于包含许多项目的列表,在单击更新按钮后,它会使屏幕返回到列表的顶部,这使得 select 许多项目变得不切实际。有什么方法可以在 <p:commandLink>
中提供更新特定行吗?
<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 中,有几种方法可以完成您的需要。较新版本的 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
并更新它,就像在这个例子中一样,解决了这个问题。