Подтвердить что ты не робот

Потенциальный метод, вызывающий после завершения запроса POST (в основном Ajaxical)

При выполнении операций CRUD с использованием JSF/PrimeFaces обычно необходим общий метод, который сбрасывает управляемые поля/свойства bean, который должен быть вызван в основном после того, как одна такая операция будет успешно завершена, чтобы поля в базе данных bean reset к их исходному (по умолчанию) значению.

Воображаемый код:

@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.
}

Метод 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"/>

Следующие события AJAX, связанные с <p:dataTable>, также требуют вызова метода 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, успешно завершил свое задание?

4b9b3361

Ответ 1

JSF для этого не имеет тега.

В идеале вы хотели бы иметь что-то вроде <f:event type="postInvokeAction" listener="#{bean.reset}">, непосредственно привязанного к <p:dataTable>. Но это событие не существует в JSF 2.2. OmniFaces имеет один, но поддерживается только на UIViewRoot, UIForm, UIInput и UICommand.

<f:phaseListener> приближается, но привязывается к UIViewRoot напрямую, даже если вы помещаете его внутри <p:dataTable>. И для этого требуется целая реализация PhaseListener.

<f:view afterPhase> кажется лучшим выбором. Вам потребуется дополнительная проверка идентификатора фазы и исходного компонента.

<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.
    // ...
}

(binding при необходимости можно заменить жестко запрограммированным идентификатором клиента таблицы)


Я понимаю, что это неудобно. Итак, для предстоящего OmniFaces 2.2 у меня изменен существующий InvokeActionEventListener, чтобы поддержать этот вариант использования. Теперь он поддерживает привязку к любому UIComponent.

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