ajax 提交后发生验证错误时保持 p:dialog 打开
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9195756/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Keep p:dialog open when a validation error occurs after submit
提问by JOTN
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.
我希望能够做的是让 mbean.saveMethod 以某种方式阻止对话框在出现问题时关闭,并且只通过咆哮输出消息。在这种情况下,验证器无济于事,因为在将保存提交到后端服务器之前,无法判断 someValue 是否有效。目前我使用可见属性执行此操作并将其指向 mbean 中的布尔字段。这有效,但它使用户界面变慢,因为弹出或关闭对话框需要点击服务器。
回答by BalusC
The onsuccessruns if ajax request itself was successful (i.e. there's no network error, uncaught exception, etc), not if action method was successfully invoked.
在onsuccess运行,如果AJAX请求本身是成功的(即有没有网络故障,未捕获的异常等),如果不采取行动方法成功地调用。
Given a <p:dialog widgetVar="testDialog">, you could remove the onsuccessand replace it by PrimeFaces RequestContext#execute()inside saveMethod():
给定一个<p:dialog widgetVar="testDialog">,你可以删除onsuccess和替换PrimeFaces它RequestContext#execute()里面saveMethod():
if (success) {
RequestContext.getCurrentInstance().execute("PF('testDialog').hide()");
}
Note: PF()was introduced in PrimeFaces 4.0. In older PrimeFaces versions, you need testDialog.hide()instead.
注意:PF()在 PrimeFaces 4.0 中引入。在较旧的 PrimeFaces 版本中,您需要testDialog.hide()改为。
If you prefer to not clutter the controller with view-specific scripts, you could use oncompleteinstead which offers an argsobject which has a boolean validationFailedproperty:
如果您不想使用特定于视图的脚本使控制器混乱,则可以oncomplete改用它提供args具有布尔validationFailed属性的对象:
<p:commandButton ...
oncomplete="if (args && !args.validationFailed) PF('testDialog').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 validationFailedfrom 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, testDialog)"as shown in Keep <p:dialog> open when validation has failed.
该if (args)检查是必要的,因为在发生 ajax 错误时它可能不存在,从而在您尝试从中获取时导致新的 JS 错误validationFailed;由于此答案中解释的原因,&替代&是强制性的,如有必要,请重构您调用的 JS 函数,如在验证失败时保持 <p:dialog> 打开所示。oncomplete="hideDialogOnSuccess(args, testDialog)"
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 validationFailedto truefrom inside backing bean action method by explicitly invoking FacesContext#validationFailed(). E.g.
如果然而,没有验证错误和操作方法被成功触发,而你仍想保留,比如,因为异常的服务方法调用的对话框打开,这时你可以手动触发validationFailed以true通过明确从内支持bean的操作方法调用FacesContext#validationFailed(). 例如
FacesContext.getCurrentInstance().validationFailed();
回答by soltysh
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:
我刚刚用谷歌搜索了这个解决方案。基本上这个想法是使用 actionListener 而不是按钮的动作,并在支持 bean 中添加回调参数,然后将检查按钮的 oncomplete 方法。示例部分代码:
JSF first:
首先是JSF:
<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 :)
希望这对某人有所帮助:)
回答by Alonso Dominguez
Using the oncompleteattribute from your command button and really simple script will help you a lot.
使用oncomplete命令按钮中的属性和非常简单的脚本会对您有很大帮助。
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>
回答by Antaeus
I use this solution:
我使用这个解决方案:
JSF code:
JSF代码:
<p:dialog ... widgetVar="dlgModify" ... >
...
<p:commandButton value="Save" update="@form" actionListener="#{AdminMB.saveTable}" />
<p:commandButton value="Cancel" oncomplete="PF('dlgModify').hide();"/>
Backing bean code:
支持bean代码:
public void saveTable() {
RequestContext rc = RequestContext.getCurrentInstance();
rc.execute("PF('dlgModify').hide()");
}
回答by Luís Soares
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)}" />
回答by makkasi
The easiest solution is to not have any "widget.hide", neither in onclick, neither in oncomplete. Remove the hide functions and just put
最简单的解决方案是没有任何“widget.hide”,既不在 onclick 中,也不在 oncomplete 中。删除隐藏功能,只需放置
visible="#{facesContext.validationFailed}"
for the dialog tag
对于对话框标签

