0

我有一个<p:dataTable>incell 编辑,它包含 2 列,每列都有一个<h:selectOneMenu>加上第三个 Edit 列。第二个<h:selectOneMenu>取决于第一个中的选择<h:selectOneMenu>。当一行处于输入/编辑模式时,更改第一个中的值<h:selectOneMenu>应该更新第二个中的列表,<h:selectoneMenu>然后我应该能够继续更改第二个中的值,然后保存对行的更改。

我的问题是,如果第一个中的值<h:selectOneMenu>发生更改,则第二个<p:selectOneMenu>中的列表会正确更新,但是当我单击<p:rowEditor>列中的复选图标(保存更改)时没有任何反应,该行保持在编辑模式。支持 bean 中的 RowEditEvent 侦听器(显然)也没有被调用。但是,我仍然可以单击关闭图标将行切换回输出模式,但是没有保存任何内容。

如果我只更改第二个中<h:selectOneMenu>的值而不更改第一个中的值<h:selectOneMenu>,那么保存更改就没有问题。

以下是代码片段,经过简化,但由于几天的测试代码仍然“脏”:

xhtml:

<h:form id="dataListForm">
<p:dataTable id="dataTable" value="#{bean.rdcList}" var="rdc" >
    <p:ajax event="rowEdit" listener="#{bean.onRowEdit}" />
    <f:facet name="header">
        Data List
    </f:facet>
    <p:column headerText="Agency">
        <p:cellEditor>
            <f:facet name="output">
                <h:outputText value="#{rdc.agency.descr}" />
            </f:facet>
            <f:facet name="input">
                <h:selectOneMenu value="#{rdc.agency.id}" valueChangeListener="#{bean.agChanged}">
                    <f:selectItems value="#{bean.agenciestab}" var="ag" itemValue="#{ag.id}" itemLabel="#{ag}" />
                    <p:ajax event="change" update="zoneSelect" />
                </h:selectOneMenu>
            </f:facet>
        </p:cellEditor>
    </p:column>
    <p:column headerText="Zone">
        <p:cellEditor>
            <f:facet name="output">
                <h:outputText value="#{rdc.zone.id} - #{rdc.zone.name}" />
            </f:facet>
            <f:facet name="input">
                <h:selectOneMenu id="zoneSelect" value="#{rdc.zone.id}" valueChangeListener="#{bean.zChanged}">
                    <f:selectItems value="#{bean.zonestab}" var="z" itemValue="#{z.id}" itemLabel="#{z}" />
                </h:selectOneMenu>
            </f:facet>
        </p:cellEditor>
    </p:column>
    <p:column headerText="Edit">
        <p:rowEditor />
    </p:column>
</p:dataTable>

bean:

@ManagedBean(name = "bean")
@SessionScoped

public class Bean implements Serializable {
.
.
/* Init */
@PostConstruct
public void init() {
    aChanged = false;
    zChanged = false;
    edited = false;
    agenciestab = new ArrayList<SelectItem>();
    for (Agency agency : agencyDao.all()) {
        agenciestab.add(new SelectItem(agency.getId(), agency.getDescr()));
    }
}

/* Listeners */
public void agChanged(ValueChangeEvent event) {
    aChanged = true;
    selectedAgency = agencyDao.get(Integer.valueOf(event.getNewValue()
            .toString()));
    zonestab = new ArrayList<SelectItem>();
    if (selectedAgency != null) {
        for (Zone zone : zoneDao.getByDistrict(selectedAgency.getDistrict())) {
            zonestab.add(new SelectItem(zone.getId(), zone.getZone()+ " - " + zone.getName()));
        }
    } else {
        for (Zone zone : zoneDao.getByDistrict(rdcList.getRowData().getAgency().getDistrict())) {
            zonestab.add(new SelectItem(zone.getId(), zone.getZone()+ " - " + zone.getName()));
        }
    }
}

public void zChanged(ValueChangeEvent event) {
    zChanged = true;
    selectedZone = zoneDao.get(Integer.valueOf(event.getNewValue().toString()));
}

public void onRowEdit(RowEditEvent event) {
    edited = true;
    Rdc rdc = (Rdc) event.getObject();
    if (aChanged) {
        rdc.setAgency(selectedAgency);
        aChanged = false;
    }
    if (zChanged) {
        rdc.setZone(selectedZone);
        zChanged = false;
    }
    try {
        rdcDao.saveOrUpdate(rdc);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

/* Getters & Setters */
public DataModel<Rdc> getRdcList() {
    if (rdcList == null) {
        rdcList = new ListDataModel<Rdc>(rdcDao.getBatchRdc(batchBean.getCurBatch().getId()));
    } else {
        rdcList.setRowIndex(0);
        if (rdcList.isRowAvailable() && rdcList.getRowData().getBatch().getId().equals(batchBean.getCurBatch().getId())) {
            if (edited) {
                edited = false;
                rdcList = new ListDataModel<Rdc>(
                        rdcDao.getBatchRdc(batchBean.getCurBatch().getId()));
            }
        } else {
            rdcList = new ListDataModel<Rdc>(rdcDao.getBatchRdc(batchBean.getCurBatch().getId()));
        }
    }
    return rdcList;
}

public void setRdcList(DataModel<Rdc> rdcList) {
    this.rdcList = rdcList;
}

public ArrayList<SelectItem> getAgenciestab() {
    return agenciestab;
}

public void setAgenciestab(ArrayList<SelectItem> agenciestab) {
    this.agenciestab = agenciestab;
}

public ArrayList<SelectItem> getZonestab() {
    zonestab = new ArrayList<SelectItem>();
    if (aChanged && selectedAgency != null) {
        for (Zone zone : zoneDao.getByDistrict(selectedAgency.getDistrict())) {
            zonestab.add(new SelectItem(zone.getId(), zone.getZone()+ " - " + zone.getName()));
        }
    } else if (!aChanged) {
        for (Zone zone : zoneDao.getByDistrict(rdcList.getRowData().getAgency().getDistrict())) {
            zonestab.add(new SelectItem(zone.getId(), zone.getZone()+ " - " + zone.getName()));
        }
    }

    return zonestab;
}

public void setZonestab(ArrayList<SelectItem> zonestab) {
    this.zonestab = zonestab;
}
/* other getters & setters */
}

我正在使用 primefaces-3.1.1、mojarra-2.1.3-FCS 和 Tomcat 7.0.26

我哪里做错了?有没有一种更清洁、更好的方法来实现我想要实现的目标?

4

1 回答 1

2

您正在 getter 方法中执行业务逻辑。在您的特定情况下,每次调用数据表的 getter 时,您都将数据表行索引设置为 0。这很可能是您的具体问题的根本原因。这样,JSF 将无法找到在第一行以外的行上执行的任何操作。您绝对不应该在 getter 方法中执行业务逻辑。每当 EL 需要计算表达式时,都会调用 getter 方法,该表达式在中等大小的数据表中可能会上升几百次。

Getter 方法应该被设计成只返回数据,仅此而已。

public List<Rdc> getRdcList() {
    return rdcList;
}

任何业务逻辑都应该在 (action)listener 方法的 (post) 构造函数中执行。第一次初始化应该进入(后)构造函数,基于最终用户(ajax)动作的一次性更改应该进入(动作)监听器方法。在极端情况下,您应该使用最高延迟加载。

也可以看看:


与具体问题无关valueChangeListener,这不是您所拥有的目的的正确工具。而是使用<p:ajax listener="#{bean.changed}">. 该模型已经使用此时提交的值进行了更新。

于 2012-06-19T13:49:25.440 回答