在POST(基本上是Ajaxical)请求完成后调用的潜在方法

时间:2015-08-17 18:57:33

标签: jsf primefaces

在使用JSF / PrimeFaces执行CRUD操作时,通常需要一种重置托管bean字段/属性的常用方法,基本上在成功完成一个此类操作后调用,以便将支持bean中的字段重置为其初始(默认)值。

虚构代码:

@Named
@ViewScoped
public class Bean extends LazyDataModel<Entity> implements Serializable {

    @Inject
    private Service service; // EJB.

    // Holds a list of selected rows in a <p:dataTable>.
    private List<Entity> selectedValues; // Getter & setter.

    private String someField; // Getter & setter.
    // Other fields depending upon the business requirement.

    public Bean() {}

    @PostConstruct
    private void init() {
        // Do something.
    }

    @Override
    public List<Entity> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, Object> filters) {
        setRowCount(service.rowCount());
        // Other complex logic as and when required.
        return service.getList(first, pageSize, map, filters); // Returns a List<Entity>.
    }

    // Resets fields to their default value.
    public void reset() {
        someField = null;
        selectedValues = null;
        // Reset other fields to their default value.
    }

    // Add (insert submitted values to the database).
    // This method is basically bound to an action(Listener) of <p:commandButton>.
    public void submit() {
        if (service.insert(someField)) {
            // Add a FacesMessge to indicate a success.
            reset(); // Calling reset.
        } else {
            // Add a FacesMessge to indicate a failure.
        }
    }

    // Update the database using submitted values.
    public void onRowEdit(RowEditEvent event) {
        if (event.getObject() instanceof Entity) {
            Entity entity = (Entity) event.getObject();
            Entity newEntity = service.update(entity);

            if (newEntity != null) {
                // Update the model.
                // Other things like adding a FacesMessage to indicate a success.
            } else {
                // Add a FacesMessage to warn against the null entity returned by the service layer.
            }
        } else {
            // Add a FacesMessage to indicate a failure.
        }

        reset(); // Finally reset the fields to their initial/default value.
    }

    // Similarly, performing the delete operation also requires to call the reset() method.
}

执行“insert”的submit()方法基本上与JSF / PrimeFaces命令组件相关联,如<p/h:commandButton><p/h:commandLink>。如。。

<p:inputText value="#{bean.someField}"/>

<p:commandButton value="Submit"
                 actionListener="#{bean.submit}"
                 oncomplete="if(args &amp;&amp; !args.validationFailed) {updateTable();}"/>

<!-- Updating a p:dataTable in question after the above p:commandButton completes. -->
<p:remoteCommand name="updateTable" update="dataTable" process="@this"/>

以下与<p:dataTable>相关联的AJAX事件也需要调用reset()方法。

<p:ajax event="rowEdit"
        onstart="..."
        oncomplete="..."
        update="..."
        listener="#{bean.onRowEdit}"/>

<p:ajax event="rowEditCancel"
        onstart="..."
        oncomplete="..."
        update="..."
        listener="#{bean.reset}"/>

<p:ajax event="page"
        onstart="..."
        oncomplete="..."
        update="..."
        listener="#{bean.reset}"/>

<p:ajax event="sort"
        onstart="..."
        oncomplete="..."
        update="..."
        listener="#{bean.reset}"/>

<p:ajax event="filter"
        onstart="..."
        oncomplete="..."
        update="..."
        listener="#{bean.reset}"/>

可以看出,reset()方法需要仔细记忆,因为它是从几个地方调用的。这种方式有点难以维护。

在每个POST请求执行其中一个CRUD操作成功完成其作业后,是否存在自动调用此类常用方法的方法?

1 个答案:

答案 0 :(得分:8)

JSF没有任何标签。

理想情况下,您希望将<f:event type="postInvokeAction" listener="#{bean.reset}">直接附加到<p:dataTable>。但是JSF 2.2中不存在该事件。 OmniFaces有一个,但仅在UIViewRootUIFormUIInputUICommand支持。

<f:phaseListener>接近,但它会直接附加到UIViewRoot,即使您将其放在<p:dataTable>内。并且,它需要整个PhaseListener实现。

<f:view afterPhase>似乎是您最好的选择。您只需要对相位ID和源组件进行一些额外的检查。

<p:dataTable binding="#{table}" ...>
    <f:view afterPhase="#{bean.reset(table)}" />
    <p:ajax ... />
    <p:ajax ... />
    <p:ajax ... />
    <p:ajax ... />
    ...
</p:dataTable>
public void reset(UIData table) {
    FacesContext context = FacesContext.getCurrentInstance();

    if (context.getCurrentPhaseId() != PhaseId.INVOKE_APPLICATION) {
        return;
    }

    String source = context.getExternalContext().getRequestParameterMap().get("javax.faces.source");

    if (!table.getClientId(context).equals(source)) {
        return;
    }

    // Reset logic here.
    // ...
}

(如果需要,可以用硬编码的表客户端ID替换binding

我明白这很尴尬。因此,对于即将到来的OmniFaces 2.2,我altered现有的InvokeActionEventListener也支持此用例。它现在支持附加在任何UIComponent上。

<p:dataTable ...>
    <f:event type="postInvokeAction" listener="#{bean.reset}" />
    <p:ajax ... />
    <p:ajax ... />
    <p:ajax ... />
    <p:ajax ... />
    ...
</p:dataTable>
public void reset() {
    // ...
}