Оставьте диалоговое окно p: открытым, если после подтверждения произошла ошибка проверки - PullRequest
62 голосов
/ 08 февраля 2012

Минимальный пример диалога:

<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 ]

147 голосов
/ 08 февраля 2012

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

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


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

<p:commandButton ...
    oncomplete="if (#{not facesContext.validationFailed}) PF('testDialog').hide()" /> 
16 голосов
/ 07 ноября 2013

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

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

15 голосов
/ 08 февраля 2012

Использование атрибута 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>
7 голосов
/ 29 мая 2014

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

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()");
}
3 голосов
/ 18 апреля 2013

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

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

visible="#{facesContext.validationFailed}" 

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

...