Keep

open when validation has failed

2019-01-11 12:17发布

问题:

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?

回答1:

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


回答2:

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


回答3:

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


回答4:

to keep the dialog Open on validation Failed, you just need set the commandButton as follows:

<p:commandButton value="save"
action="#{YourBean.yourActionMethod}"
oncomplete="if (!args.validationFailed) PF('yourDialogWidgetVar').hide()"/>

I gonna leave here a complete example:

<h:form id="ad-form">
            <p:dialog id="ad-dialog" widgetVar="adDialog" modal="true" width="400"
            closeOnEscape="true" resizable="false" header="Addreass">

            <p:messages id="a-msgs" closable="true" />

            <h:panelGrid columns="2" id="ad-painel-dialog" width="100%">
                <p:outputLabel value="Country" for="country" />
                <p:inputText id="country" style="width:100%"
                    value="#{clientSaverBean.editableAddress.country}" />

                <p:outputLabel value="City" for="city" />
                <p:inputText id="city"
                    value="#{clientSaverBean.editableAddress.city}" />

                <p:outputLabel value="Zip-Code" for="zipcode" />
                <p:inputText id="zipcode"
                    value="#{clientSaverBean.editableAddress.zipCode}" />

                <p:outputLabel value="Street" for="street" />
                <p:inputTextarea id="street"
                    value="#{clientSaverBean.editableAddress.street}" />

                <p:outputLabel value="Number" for="number" />
                <p:inputText id="number"
                    value="#{clientSaverBean.editableAddress.number}" />

                <h:panelGroup />

                <f:facet name="footer">
                    <p:commandButton value="save"
                        action="#{clientSaverBean.saveAddress}"
                        process=":ad-form:ad-dialog"
                        update=":ad-form:a-msgs :ad-form:ad-painel-dialog :client-form:ad-table" 
                        oncomplete="if (!args.validationFailed) PF('adDialog').hide()"/>
                </f:facet>
            </h:panelGrid>
        </p:dialog>

    </h:form>