【问题标题】:Keep p:dialog open when a validation error occurs after submit提交后发生验证错误时保持 p:dialog 打开
【发布时间】:2023-04-03 19:52:01
【问题描述】:

最小示例对话框:

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

【问题讨论】:

    标签: ajax validation jsf primefaces dialog


    【解决方案1】:

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

    给定一个&lt;p:dialog widgetVar="yourWidgetVarName"&gt;,您可以删除onsuccess 并将其替换为saveMethod() 内的PrimeFaces RequestContext#execute()

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

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

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

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

    if (args) 检查是必要的,因为它可能在发生 ajax 错误时不存在,因此当您尝试从中获取 validationFailed 时会导致新的 JS 错误;由于this answer 中解释的原因,&amp;amp; 而不是&amp; 是必需的,如有必要,请重构您调用的JS 函数,如oncomplete="hideDialogOnSuccess(args, 'yourWidgetVarName')",如Keep <p:dialog> open when validation has failed 所示。

    如果没有验证错误并且操作方法被成功触发,并且您仍然希望保持对话框打开,例如,服务方法调用中出现异常,则可以通过显式调用FacesContext#validationFailed(),从内部支持bean 操作方法手动触发validationFailedtrue。例如

    FacesContext.getCurrentInstance().validationFailed();
    

    【讨论】:

    • 使用 RequestContext 非常有趣。我不知道你能做到。
    • oncomplete 中的表达式是需要取反。 oncomplete="if (args.validationFailed) ... "
    • @BalusC oncomplete="if(args &amp;amp;&amp;amp; !args.validationFailed) 这是我的做法。 null 是否不需要签入我的代码?
    • @BalusC,为什么在这种情况下使用 actionlistener 而不是 action ?
    • @Mah:我刚刚接管了 OP 的原始代码。问题不在于 actionListener vs action,所以我保留了 OP 的原始代码。但我同意这不是推荐的方式,对于您想知道的情况。
    【解决方案2】:

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

    JSF 优先:

    <p:commandButton actionListener="#{myBean.doAction}"
       oncomplete="if (!args.validationFailed &amp;&amp; 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);
        }
    }
    

    希望这对某人有帮助:)

    【讨论】:

    • 链接更改为here
    【解决方案3】:

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

    【讨论】:

      【解决方案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】:

        我相信这是最干净的解决方案。 这样做您无需更改按钮代码。 此解决方案覆盖了隐藏函数原型。

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

          对话框标签

          【讨论】:

          • 三点后你让我开心。谢谢!
          猜你喜欢
          • 2013-06-14
          • 2012-12-28
          • 1970-01-01
          • 2014-08-12
          • 1970-01-01
          相关资源
          最近更新 更多