JOTN JOTN - 4 months ago 55
Ajax Question

Keep p:dialog open when a validation error occurs after submit

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.

Answer

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.

You could remove the onsuccess and replace it by PrimeFaces RequestContext#execute() inside saveMethod():

if (success) {
    RequestContext.getCurrentInstance().execute("testDialog.hide()");
}

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 &amp;&amp; !args.validationFailed) 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 validationFailed from it; the &amp; 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)".


It's unfortunate that PrimeFaces does not support what RichFaces already supports: request-time re-evaluation of EL in on* attributes. You would otherwise also be able to do just this:

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