Оставьте 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 каким-то образом препятствовал закрытию диалога, если была какая-то проблема, и выводил сообщение только через рычание. Это тот случай, когда валидатор не поможет, потому что нет способа узнать, допустимо ли someValue, пока сохранение не будет отправлено на внутренний сервер. В настоящее время я делаю это с помощью атрибута visible и указываю на логическое поле в mbean. Это работает, но замедляет пользовательский интерфейс, потому что всплывающее или закрывающее диалоговое окно требует попадания на сервер.

6 ответов

Решение

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 open, когда проверка не удалась.

Это последнее решение (с небольшим переписыванием) должно работать для простого jsf h:commandButton в сочетании с f:ajax


К сожалению, PrimeFaces не поддерживает то, что RichFaces уже поддерживает: переоценка EL во время запроса on* атрибутов. В противном случае вы также можете сделать это:

<p:commandButton ...
    oncomplete="if (#{not facesContext.validationFailed}) PF('testDialog').hide()" /> 

Я только что нашел это решение. По сути, идея состоит в том, чтобы использовать 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);
    }
}

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

С использованием oncomplete Атрибут от вашей командной кнопки и действительно простой скрипт вам очень помогут.

Ваш диалог и командная кнопка будут выглядеть примерно так:

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

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

Код JSF:

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

Код боба поддержки:

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

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

visible="#{facesContext.validationFailed}" 

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

Я считаю, что это самое чистое решение. Для этого вам не нужно менять код кнопок. Это решение переопределяет прототип функции 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)}" />
Другие вопросы по тегам