提交后发生验证错误时保持 p:dialog 打开

发布于 2025-01-03 06:20:49 字数 618 浏览 0 评论 0 原文

最小示例对话框:

<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中的布尔字段。这是可行的,但它会使用户界面变慢,因为弹出或向下弹出对话框需要连接服务器。

Minimal example dialog:

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

What I want to be able to do is have the mbean.saveMethod somehow prevent the dialog from closing if there was some problem and only output a message through growl. This is a case where a validator won't help because there's no way to tell if someValue is valid until a save is submitted to a back end server. Currently I do this using the visible attribute and point it to a boolean field in mbean. That works but it makes the user interface slower because popping up or down the dialog requires hitting the server.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

伤感在游骋 2025-01-10 06:20:49

如果 ajax 请求本身成功(即没有网络错误、未捕获的异常等),则 onsuccess 运行,而不是在成功调用操作方法时运行。

给定 ,您可以删除 onsuccess 并将其替换为 PrimeFaces RequestContext#execute() saveMethod() 内:

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

注意:PF() 是在 PrimeFaces 4.0 中引入的。在较旧的 PrimeFaces 版本中,您需要 yourWidgetVarName.hide()

如果您不想让控制器与特定于视图的脚本混乱,您可以使用 oncomplete 来代替,它提供一个 args 对象,该对象具有布尔值 validationFailed property:

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

if (args) 检查是必要的,因为当发生 ajax 错误时它可能不存在,从而在您尝试从中获取 validationFailed 时导致新的 JS 错误;由于 这个答案,必要时重构为 JS 函数您可以像 oncomplete="hideDialogOnSuccess(args, 'yourWidgetVarName')" 一样调用它,如 保留 验证失败时打开

但是,如果没有验证错误并且操作方法已成功触发,并且由于服务方法调用中的异常等原因您仍然希望保持对话框打开,那么您可以手动触发 validationFailed通过显式调用 FacesContext#validationFailed()。例如

FacesContext.getCurrentInstance().validationFailed();

The onsuccess runs if ajax request itself was successful (i.e. there's no network error, uncaught exception, etc), not if action method was successfully invoked.

Given a <p:dialog widgetVar="yourWidgetVarName">, you could remove the onsuccess and replace it by PrimeFaces RequestContext#execute() inside saveMethod():

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

Note: PF() was introduced in PrimeFaces 4.0. In older PrimeFaces versions, you need yourWidgetVarName.hide() instead.

If you prefer to not clutter the controller with view-specific scripts, you could use oncomplete instead which offers an args object which has a boolean validationFailed property:

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

The if (args) check is necessary because it may be absent when an ajax error has occurred and thus cause a new JS error when you try to get validationFailed from it; the & instead of & is mandatory for the reason explained in this answer, refactor if necessary to a JS function which you invoke like oncomplete="hideDialogOnSuccess(args, 'yourWidgetVarName')" as shown in Keep <p:dialog> open when validation has failed.

If there is however no validation error and the action method is successfully triggered, and you would still like to keep the dialog open because of e.g. an exception in the service method call, then you can manually trigger validationFailed to true from inside backing bean action method by explicitly invoking FacesContext#validationFailed(). E.g.

FacesContext.getCurrentInstance().validationFailed();
眼中杀气 2025-01-10 06:20:49

使用命令按钮中的 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>

Using the oncomplete attribute from your command button and really simple script will help you a lot.

Your dialog and command button would be something similar to this:

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

An the script would be something like this:

<script type="text/javascript">
    function handleDialogSubmit(xhr, status, args) {
        if (args.validationFailed) {
            dialog.show();
        } else {
            dialog.hide();
        }
    }
</script>
花开柳相依 2025-01-10 06:20:49

我刚刚在 Google 上搜索了此解决方案。基本上,这个想法是使用actionListener而不是按钮的操作,并在支持bean中添加回调参数,然后该参数将检查按钮的oncomplete方法。示例部分代码:

首先是 JSF:

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

支持 bean:

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

希望这对某人有帮助:)

I've just googled up this solution. Basically the idea is to use actionListener instead of button's action, and in backing bean you add callback parameter which will be then check in button's oncomplete method. Sample partial code:

JSF first:

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

Backing bean:

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

Hope this helps someone :)

赠佳期 2025-01-10 06:20:49

我使用这个解决方案:

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()");
}

I use this solution:

JSF code:

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

Backing bean code:

public void saveTable() {
    RequestContext rc = RequestContext.getCurrentInstance();
    rc.execute("PF('dlgModify').hide()");
}
梦在夏天 2025-01-10 06:20:49

最简单的解决方案是不要有任何“widget.hide”,无论是在 onclick 中,还是在 oncomplete 中。删除隐藏功能并仅放置

visible="#{facesContext.validationFailed}" 

在对话框标签中

The easiest solution is to not have any "widget.hide", neither in onclick, neither in oncomplete. Remove the hide functions and just put

visible="#{facesContext.validationFailed}" 

for the dialog tag

我们只是彼此的过ke 2025-01-10 06:20:49

我相信这是最干净的解决方案。
执行此操作,您不需要更改按钮代码
该解决方案重写了隐藏函数原型。

$(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)}" />

I believe this is the cleanest solution.
Doing this you don't need to change your buttons code.
This solution overrides the hide function prototype.

$(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();
    };
});

This way, you can keep your code like:

<p:commandButton value="Save" oncomplete="videoDetalheDialogJS.hide();" 
   actionListener="#{videoBean.saveVideo(video)}" />
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文