JSF 数据表:通过单个命令按钮提交多行
JSF Datatable: Multiple row submit via a single command button
我在使用 JSF 和数据表时遇到了一些问题。在我的 bean 中,我有一个对象列表,这些对象依赖于数据表显示在视图中。对象是
很简单,每一个都是由一个整数(id)和一个字符串(the
评论)。
最终目标是将完整的对象列表打印给将同时编辑一行或多行(通过 h:inputtext 字段)的用户,然后通过按钮提交他的更改。这就是问题所在。我已经通过依赖每行上的 Edit/Save 按钮每次编辑一行来使用 "successfully" 数据表,但在这种情况下不适用,因为最终用户将面临总共超过 500 行。
这是我使用的代码(经过简化和提取)
豆子:
@ManagedBean
@RequestedScope
public class VlanBean {
private DataModel<VlanWrapper> model;
private List<VlanWrapper> vlans = new ArrayList<VlanWrapper>();
public VlanBean() {
vlans.add(new VlanWrapper(1, ""));
vlans.add(new VlanWrapper(2, "Prova2-2"));
vlans.add(new VlanWrapper(3, ""));
vlans.add(new VlanWrapper(4, ""));
vlans.add(new VlanWrapper(5, ""));
vlans.add(new VlanWrapper(6, "Prova3"));
vlans.add(new VlanWrapper(7, ""));
vlans.add(new VlanWrapper(8, ""));
}
public void commitChanges()
{
System.out.println("Before Model ");
for (VlanWrapper vw : model)
{
System.out.println("ModelOF " + vw.getId() + " - " + vw.getProject() + " - changed: " + vw.changed + ";");
}
}
public DataModel<VlanWrapper> getModel() {
if (model == null)
model = new ListDataModel<VlanWrapper>(vlans);
return model;
}
public void setModel(DataModel<VlanWrapper> model) {
this.model = model;
}
public class VlanWrapper
{
private boolean changed;
private int id;
private String project;
public VlanWrapper(int id, String prj)
{
this.id = id;
this.project = prj;
changed = false;
}
public String getProject() {
return project;
}
public void setProject(String project) {
System.out.println("Setting PRJ..");
changed = true;
this.project = project;
}
public int getId() {
return id;
}
public boolean isChanged() {
return changed;
}
}
}
查看:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
</h:head>
<h:body>
<f:view>
<h:panelGroup>
<h:form>
<h:commandButton value="Commit changes to DB" action="#{VlanBean.commitChanges}">
</h:commandButton>
</h:form>
<h:dataTable value="#{VlanBean.model}" var="vlans">
<h:column><f:facet name="header">ID</f:facet>#{vlans.id}</h:column>
<h:column><f:facet name="header">Project</f:facet>
<h:inputText value="#{vlans.project}" immediate="true"/>
</h:column>
</h:dataTable>
</h:panelGroup>
</f:view>
</h:body>
</html>
问题是我在视图上所做的所有更改都没有反映在 bean 中,而且我还没有找到任何有用的 hint/post(有些建议 ajax 强制更新,其他javascript,但我没有让它们中的任何一个工作,而且没有人真正接近我想要的用途)。
我也尝试过 ui:repeat,但我有同样的行为。有 ideas/suggestion 吗?我没有义务使用数据表,所以我向其他人开放 solution/approach!
提前致谢,
阿尔贝托
从您的代码中,您应该收到一条警告,说明您的 <h:inputText
应该有一个 <f:form
作为父级;它周围没有任何形式,而您所拥有的形式只是围绕 <h:commandButton
使用任何类型的 Iteration
UIComponent,您可以获得您想要的行为,尽管通常您使用 <h:datatable
。您可以执行以下操作,尽管您必须先 select 要编辑的行,但我相信您可以自己找到解决方案:
我向你的实体添加了另一个 属性 VlanWrapper
:
private boolean changed;
private boolean edit;
private int id;
private String project;
// setter 和 getter ....
您的小脸可能是这样的:
<h:form>
<h:dataTable value="#{meod.vlans}" var="v" >
<h:column>
<f:facet name="header">Id</f:facet>
<h:outputLabel value="#{v.id}" />
</h:column>
<h:column>
<f:facet name="header">Project</f:facet>
<h:outputLabel rendered="#{not v.edit}" value="#{v.project}" />
<h:inputText rendered="#{v.edit}" value="#{v.project}" >
<f:ajax event="blur" execute="@this" listener="#{meod.addToEditedList(e)}" render="@all">
<f:param name="vlanedit" value="#{v.id}" />
<f:param name="vlanproject" value="#{v.project}" />
</f:ajax>
</h:inputText>
</h:column>
<h:column>
<f:facet name="header">Edit</f:facet>
<h:commandButton value="Edit" action="#{meod.edit(v)}">
<f:ajax render="@form" />
</h:commandButton>
</h:column>
</h:dataTable>
<h:commandButton value="Finalize Edit" action="#{meod.editSubmit()}" />
</h:form>
我之所以说你必须 select 你想编辑的行是因为当你按下 edit
按钮时,整个表格都会更新所以只要玩弄你的东西想要更新,这应该可以。
辅助豆:
@ManagedBean
@ViewScoped
public class Meod {
private List<VlanWrapper> vlans;
public Meod() {
vlans = new ArrayList<>();
for (int i = 0; i < 11; i++) {
vlans.add(new VlanWrapper(i, "Project " + i));
}
}
public void addToEditedList(AjaxBehaviorEvent e) {
Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
int id = Integer.valueOf(params.get("vlanedit"));
String newProject = params.get("vlanproject");
updateVlanInView(id, newProject);
}
private void updateVlanInView(int id, String proj) {
vlans.stream().filter(v -> v.getId() == id).forEach(v -> v.setProject(proj));
}
public void edit(VlanWrapper vlan2Edit) {
vlan2Edit.setEdit(true);
}
public void editSubmit() {
vlans.forEach((v) -> v.setEdit(false));
}
public List<VlanWrapper> getVlans() {
return vlans;
}
public void setVlans(List<VlanWrapper> vlans) {
this.vlans = vlans;
}
}
您可以通过多种方式实现这一目标...可能是更好的方式,但总结一下:
- 创建一个数据表来迭代你的对象
- 确保你的
<h:commandXXX
和 EditableValueHolder
都在表格中。
- "new"属性
edit
是判断是否渲染输入而不是输出的文本组件
- 在更改后使用 DBService 更新值。
希望这对您有所帮助。
将您的 </h:form>
标签移到数据表之后。这现在将包括您的更改,并且现在将正确调用 setProject 方法。
<h:panelGroup>
<h:form>
<h:commandButton value="Commit changes to DB" action="#{VlanBean.commitChanges}">
</h:commandButton>
<h:dataTable value="#{VlanBean.model}" var="vlans">
<h:column><f:facet name="header">ID</f:facet>#{vlans.id}</h:column>
<h:column><f:facet name="header">Project</f:facet>
<h:inputText value="#{vlans.project}" immediate="true"/>
</h:column>
</h:dataTable>
</h:form>
</h:panelGroup>
我在使用 JSF 和数据表时遇到了一些问题。在我的 bean 中,我有一个对象列表,这些对象依赖于数据表显示在视图中。对象是 很简单,每一个都是由一个整数(id)和一个字符串(the 评论)。
最终目标是将完整的对象列表打印给将同时编辑一行或多行(通过 h:inputtext 字段)的用户,然后通过按钮提交他的更改。这就是问题所在。我已经通过依赖每行上的 Edit/Save 按钮每次编辑一行来使用 "successfully" 数据表,但在这种情况下不适用,因为最终用户将面临总共超过 500 行。
这是我使用的代码(经过简化和提取)
豆子:
@ManagedBean
@RequestedScope
public class VlanBean {
private DataModel<VlanWrapper> model;
private List<VlanWrapper> vlans = new ArrayList<VlanWrapper>();
public VlanBean() {
vlans.add(new VlanWrapper(1, ""));
vlans.add(new VlanWrapper(2, "Prova2-2"));
vlans.add(new VlanWrapper(3, ""));
vlans.add(new VlanWrapper(4, ""));
vlans.add(new VlanWrapper(5, ""));
vlans.add(new VlanWrapper(6, "Prova3"));
vlans.add(new VlanWrapper(7, ""));
vlans.add(new VlanWrapper(8, ""));
}
public void commitChanges()
{
System.out.println("Before Model ");
for (VlanWrapper vw : model)
{
System.out.println("ModelOF " + vw.getId() + " - " + vw.getProject() + " - changed: " + vw.changed + ";");
}
}
public DataModel<VlanWrapper> getModel() {
if (model == null)
model = new ListDataModel<VlanWrapper>(vlans);
return model;
}
public void setModel(DataModel<VlanWrapper> model) {
this.model = model;
}
public class VlanWrapper
{
private boolean changed;
private int id;
private String project;
public VlanWrapper(int id, String prj)
{
this.id = id;
this.project = prj;
changed = false;
}
public String getProject() {
return project;
}
public void setProject(String project) {
System.out.println("Setting PRJ..");
changed = true;
this.project = project;
}
public int getId() {
return id;
}
public boolean isChanged() {
return changed;
}
}
}
查看:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
</h:head>
<h:body>
<f:view>
<h:panelGroup>
<h:form>
<h:commandButton value="Commit changes to DB" action="#{VlanBean.commitChanges}">
</h:commandButton>
</h:form>
<h:dataTable value="#{VlanBean.model}" var="vlans">
<h:column><f:facet name="header">ID</f:facet>#{vlans.id}</h:column>
<h:column><f:facet name="header">Project</f:facet>
<h:inputText value="#{vlans.project}" immediate="true"/>
</h:column>
</h:dataTable>
</h:panelGroup>
</f:view>
</h:body>
</html>
问题是我在视图上所做的所有更改都没有反映在 bean 中,而且我还没有找到任何有用的 hint/post(有些建议 ajax 强制更新,其他javascript,但我没有让它们中的任何一个工作,而且没有人真正接近我想要的用途)。
我也尝试过 ui:repeat,但我有同样的行为。有 ideas/suggestion 吗?我没有义务使用数据表,所以我向其他人开放 solution/approach!
提前致谢, 阿尔贝托
从您的代码中,您应该收到一条警告,说明您的 <h:inputText
应该有一个 <f:form
作为父级;它周围没有任何形式,而您所拥有的形式只是围绕 <h:commandButton
使用任何类型的 Iteration
UIComponent,您可以获得您想要的行为,尽管通常您使用 <h:datatable
。您可以执行以下操作,尽管您必须先 select 要编辑的行,但我相信您可以自己找到解决方案:
我向你的实体添加了另一个 属性 VlanWrapper
:
private boolean changed;
private boolean edit;
private int id;
private String project;
// setter 和 getter ....
您的小脸可能是这样的:
<h:form>
<h:dataTable value="#{meod.vlans}" var="v" >
<h:column>
<f:facet name="header">Id</f:facet>
<h:outputLabel value="#{v.id}" />
</h:column>
<h:column>
<f:facet name="header">Project</f:facet>
<h:outputLabel rendered="#{not v.edit}" value="#{v.project}" />
<h:inputText rendered="#{v.edit}" value="#{v.project}" >
<f:ajax event="blur" execute="@this" listener="#{meod.addToEditedList(e)}" render="@all">
<f:param name="vlanedit" value="#{v.id}" />
<f:param name="vlanproject" value="#{v.project}" />
</f:ajax>
</h:inputText>
</h:column>
<h:column>
<f:facet name="header">Edit</f:facet>
<h:commandButton value="Edit" action="#{meod.edit(v)}">
<f:ajax render="@form" />
</h:commandButton>
</h:column>
</h:dataTable>
<h:commandButton value="Finalize Edit" action="#{meod.editSubmit()}" />
</h:form>
我之所以说你必须 select 你想编辑的行是因为当你按下 edit
按钮时,整个表格都会更新所以只要玩弄你的东西想要更新,这应该可以。
辅助豆:
@ManagedBean
@ViewScoped
public class Meod {
private List<VlanWrapper> vlans;
public Meod() {
vlans = new ArrayList<>();
for (int i = 0; i < 11; i++) {
vlans.add(new VlanWrapper(i, "Project " + i));
}
}
public void addToEditedList(AjaxBehaviorEvent e) {
Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
int id = Integer.valueOf(params.get("vlanedit"));
String newProject = params.get("vlanproject");
updateVlanInView(id, newProject);
}
private void updateVlanInView(int id, String proj) {
vlans.stream().filter(v -> v.getId() == id).forEach(v -> v.setProject(proj));
}
public void edit(VlanWrapper vlan2Edit) {
vlan2Edit.setEdit(true);
}
public void editSubmit() {
vlans.forEach((v) -> v.setEdit(false));
}
public List<VlanWrapper> getVlans() {
return vlans;
}
public void setVlans(List<VlanWrapper> vlans) {
this.vlans = vlans;
}
}
您可以通过多种方式实现这一目标...可能是更好的方式,但总结一下:
- 创建一个数据表来迭代你的对象
- 确保你的
<h:commandXXX
和EditableValueHolder
都在表格中。 - "new"属性
edit
是判断是否渲染输入而不是输出的文本组件 - 在更改后使用 DBService 更新值。
希望这对您有所帮助。
将您的 </h:form>
标签移到数据表之后。这现在将包括您的更改,并且现在将正确调用 setProject 方法。
<h:panelGroup>
<h:form>
<h:commandButton value="Commit changes to DB" action="#{VlanBean.commitChanges}">
</h:commandButton>
<h:dataTable value="#{VlanBean.model}" var="vlans">
<h:column><f:facet name="header">ID</f:facet>#{vlans.id}</h:column>
<h:column><f:facet name="header">Project</f:facet>
<h:inputText value="#{vlans.project}" immediate="true"/>
</h:column>
</h:dataTable>
</h:form>
</h:panelGroup>