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:commandXXXEditableValueHolder 都在表格中。
  • "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>