Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keep <p:dialog> open when validation has failed

I have a CRUD page which shows data from a query (a List of domain objects) in a Primefaces datatable.

<p:dataTable 
                id="negozi" 
                var="n" 
                value="#{nController.theListFromQuery}" 
                rowKey="#{n.id}"
                selection="#{nController.selected}" 
                selectionMode="single">

                <p:column headerText="Field1">
                    <h:outputText value="#{n.f1}" />
                </p:column>
                <p:column headerText="Field2">
                    <h:outputText value="#{n.f2}" />
                </p:column>
<p:column style="width:4%">
                    <p:commandButton 
                        actionListener="#{nController.prepareEdit(n)}"
                        update=":editDialogId" 
                        oncomplete="editDialog.show()" 
                        value="Edit" />
                </p:column>
...

By clicking on the edit button a dialog will be shown:

    <p:dialog 
                header="Edit N" 
                widgetVar="editDialog" 
                id="editDialogId">

                    <h:form id="formDialog">

                        <h:panelGrid id="editDialogTable" columns="2" cellpadding="10" style="margin:0 auto;">

                            <p:outputLabel for="field1" value="F1:" />
                            <p:inputText id="field1" value="#{nController.selected.f1}" />
                            <p:outputLabel for="field2" value="F2:" />
                            <p:inputText id="field2" value="#{nController.selected.f2}" />
<p:commandButton 
                        value="Confirm" 
                        actionListener="#{nController.doEdit}" 
                        update=":form" 
                        oncomplete="editDialog.hide()"
                        rendered="#{nController.selected.id!=null}" />                  
...

It works. Now I want to make F1 a required field.

I add the "required" attribute to the inputText field and what happens?

When I try to confirm the form without the required field, the entity is not edited (that's right) but the dialog is closed (that's NOT right!)

When I reopen the dialog I can see the red highlight on the required (and invalid) field.

What I want is to prevent the dialog closing if the form is invalid.

Do I have to write some JS or will JSF help me?

like image 755
Fabio B. Avatar asked Jan 14 '13 22:01

Fabio B.


3 Answers

The PrimeFaces ajax response puts an args object in the scope which has a validationFailed property. You could just make use of it.

oncomplete="if (args &amp;&amp; !args.validationFailed) PF('editDialog').hide()"

(the args precheck is necessary to not cause a JS error when an exception is thrown during request)

You could refactor it to a reusable JS function as follows.

oncomplete="hideDialogOnSuccess(args, 'editDialog')"
function hideDialogOnSuccess(args, dialogWidgetVar) {
    if (args && !args.validationFailed) {
        PF(dialogWidgetVar).hide();
    }
}
like image 134
BalusC Avatar answered Nov 11 '22 15:11

BalusC


this post is now three years old, but I have found helpful, so my findings may help others.

In PF 5.x at least, it seems that the solution provided by BalusC has to be modified in two ways. (1) add the "args" argument to the call in oncomplete event hander, and (2) use the PF primefaces primitive to identify the widget in PF tables. Here is the code I am using:

oncomplete="hideDialogOnSuccess(args, PF('editDialog'))"

function hideDialogOnSuccess(args, dialogWidgetVar) {
    if (args && !args.validationFailed) {
        dialogWidgetVar.hide();
    }
}
like image 6
LaurentV Avatar answered Nov 11 '22 13:11

LaurentV


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)}" />
like image 3
Luís Soares Avatar answered Nov 11 '22 15:11

Luís Soares