Сохранять p: диалог открывается, когда возникает ошибка проверки после отправки

Диалоговое окно с минимальным примером:

<p:dialog header="Test Dialog"  
          widgetVar="testDialog"> 
  <h:form> 
    <p:inputText value="#{mbean.someValue}"/> 

    <p:commandButton value="Save" 
                     onsuccess="testDialog.hide()" 
                     actionListener="#{mbean.saveMethod}"/> 
  </h:form>       
</p:dialog> 

То, что я хочу сделать, - это mbean.saveMethod каким-то образом предотвратить закрытие диалога, если возникла какая-то проблема, и выводить сообщение только через рычание. Это случай, когда валидатор не поможет, потому что нет способа узнать, действителен ли какой-либо валид, пока не будет сохранено резервное копирование на задний сервер. В настоящее время я делаю это с использованием видимого атрибута и указываю его на логическое поле в mbean. Это работает, но это делает пользовательский интерфейс более медленным, потому что для всплытия или по диалогу требуется поражение сервера.

Ответ 1

onsuccess запускается, если сам запрос ajax был успешным (т.е. нет сетевых ошибок, необработанных исключений и т.д.), А не если метод действия был успешно вызван.

Имея <p:dialog widgetVar="testDialog">, вы можете удалить onsuccess и заменить его PrimeFaces RequestContext#execute() внутри saveMethod():

if (success) {
    RequestContext.getCurrentInstance().execute("PF('testDialog').hide()");
}

Примечание: PF() был представлен в PrimeFaces 4.0. В старых версиях PrimeFaces вместо этого вам нужен testDialog.hide().

Если вы предпочитаете не загромождать контроллер скриптами, специфичными для представления, вы можете использовать вместо этого oncomplete, который предлагает объект args, который имеет логическое свойство validationFailed:

<p:commandButton ...
    oncomplete="if (args &amp;&amp; !args.validationFailed) PF('testDialog').hide()" />

Проверка if (args) необходима, потому что она может отсутствовать при возникновении ошибки AJAX и, таким образом, вызывать новую ошибку JS, когда вы пытаетесь получить validationFailed от нее; &amp; вместо & является обязательным по причине, описанной в этом ответе, при необходимости измените рефакторинг на функцию JS, которую вы вызываете, как oncomplete="hideDialogOnSuccess(args, testDialog)", как показано в Keep & lt; p: диалоговое окно & GT; открыть при сбое проверки.

Однако, если нет ошибки валидации и метод действия успешно запущен, и вы все равно хотели бы оставить диалог открытым, например, из-за. исключение в вызове метода службы, затем вы можете вручную вызвать validationFailed - true изнутри метода действия вспомогательного компонента, явно вызвав FacesContext#validationFailed(). Э.Г.

FacesContext.getCurrentInstance().validationFailed();

Ответ 2

Я только что погуглил это решение. По сути, идея состоит в том, чтобы использовать actionListener вместо действия кнопки, и в компоненте поддержки вы добавляете параметр обратного вызова, который затем будет проверяться в методе кнопки oncomplete. Пример частичного кода:

JSF первый:

<p:commandButton actionListener="#{myBean.doAction}"
   oncomplete="if (!args.validationFailed &amp;&amp; args.saved) schedulesDialog.hide();" />

бэк-бэк:

public void doAction(ActionEvent actionEvent) {
    // do your stuff here...
    if (ok) {
        RequestContext.getCurrentInstance().addCallbackParam("saved", true);
    } else {
        RequestContext.getCurrentInstance().addCallbackParam("saved", false);
    }
}

Надеюсь, это поможет кому-то :)

Ответ 3

Использование атрибута oncomplete из вашей командной кнопки и действительно простой script поможет вам многое.

Ваша кнопка диалога и команды будет похожа на это:

<p:dialog widgetVar="dialog">
   <h:form id="dialogView">
       <p:commandButton id="saveButton" icon="ui-icon-disk"
           value="#{ui['action.save']}"
           update=":dataList :dialogView"
           actionListener="#{mbean.save()}"
           oncomplete="handleDialogSubmit(xhr, status, args)" />
   </h:form>
 </p:dialog>

А script будет примерно таким:

<script type="text/javascript">
    function handleDialogSubmit(xhr, status, args) {
        if (args.validationFailed) {
            dialog.show();
        } else {
            dialog.hide();
        }
    }
</script>

Ответ 4

Я использую это решение:

Код JSF:

<p:dialog ... widgetVar="dlgModify" ... >
...
<p:commandButton value="Save" update="@form" actionListener="#{AdminMB.saveTable}" />
<p:commandButton value="Cancel" oncomplete="PF('dlgModify').hide();"/>

Резервное копирование bean кода:

public void saveTable() {
    RequestContext rc = RequestContext.getCurrentInstance();
    rc.execute("PF('dlgModify').hide()");
}

Ответ 5

Я считаю, что это самое чистое решение. Для этого вам не нужно менять код кнопок. Это решение переопределяет прототип функции hide.

$(document).ready(function() {
    PrimeFaces.widget.Dialog.prototype.originalHide = PrimeFaces.widget.Dialog.prototype.hide; // keep a reference to the original hide()
    PrimeFaces.widget.Dialog.prototype.hide = function() {
        var ajaxResponseArgs = arguments.callee.caller.arguments[2]; // accesses oncomplete arguments
        if (ajaxResponseArgs && ajaxResponseArgs.validationFailed) {
            return;  // on validation error, prevent closing
        }
        this.originalHide();
    };
});

Таким образом, вы можете сохранить свой код следующим образом:

<p:commandButton value="Save" oncomplete="videoDetalheDialogJS.hide();" 
   actionListener="#{videoBean.saveVideo(video)}" />

Ответ 6

Самое простое решение - не иметь никакого "widget.hide", ни в onclick, ни в oncomplete. Удалите скрытые функции и просто поместите

visible="#{facesContext.validationFailed}" 

для тега диалога