0

I am using Bootsfaces for displaying a modal dialog. Inside the modal dialog there is a field (actually it's b:inputTextarea) and a command button which uses Ajax to submit the data. I want to make sure that the user has entered something to the text field before submitting. If the field is empty then the modal should not be closed and the submit should not happen, if the field is non-empty then the dialog should be closed and the submitting should happen Ajax-style.

Due to an issue with Bootsfaces 1.4.2 I cannot use b:command to do the Ajax-part. I have to use the standard way with h:commandButton and f:ajax.

I am trying to solve my problem like this:

<b:form>
    <!--  section that gets updated by ajax-request -->
    <b:panel id="updateSection">
        <h:outputText value="#{testBean.value1}" />
        <b:button value="open dialog" onclick="$('.pseudoClass').modal()" />
    </b:panel>
    <!-- modal dialog -->
    <b:modal title="model" styleClass="pseudoClass" closable="false" closeOnEscape="true">
        <b:panel id="modalOutput"><h:inputText value="#{testBean.value1}" /></b:panel>
        <f:facet name="footer">
            <!-- cancel button -->
            <b:button largeScreen="half" value="cancel" dismiss="modal" onclick="return false;" />
            <!-- submit button ajax-style -->
            <h:commandButton value="submit" action="#{testBean.save()}" onclick="validateModalDialog();">
                <f:ajax render="updateSection" execute="@this modalOutput" onevent="closeModalDialog" />
            </h:commandButton>
            <!-- scripts to close & validate modal dialog -->
            <h:outputScript>
                    function closeModalDialog(data) {
                        var status = data.status;
                        if (status === 'complete') { $('.pseudoClass').modal('hide'); }
                    }
                    function validateModalDialog() {
                        alert('i get called before closing dialog');
                        return false;
                    }    
            </h:outputScript>
        </f:facet>
    </b:modal>
</b:form>

The script function validateModalDialog gets called before the modal dialog gets closed but the dialog gets closed regardless of the return value of the function (true or false).

My knowledge of JavaScript is rather limited. That was one of the reasons I chose to use JSF and Bootsfaces. But I am pretty sure there is a way to do a validation and prevent the dialog from getting closed.

How do I emulate the Bootsfaces functionality (client-side validation of text field in a modal dialog) when using the standard components h:commandButton and f:ajax?

SOLUTION:

To achieve client-side validation preventing the Ajax request from firing and the modal dialog from closing the following change needs to be done compared to my initial code:

<h:commandButton value="submit" action="#{testBean.save()}" onclick="return validateModalDialog();">
     <f:ajax render="updateSection" execute="@this modalOutput" onevent="closeModalDialog" />
</h:commandButton>
trane
  • 27
  • 1
  • 8
  • 1
    Possible duplicate of [How to validate whether my form is valid from an oncomplete function in a b:commandButton?](https://stackoverflow.com/questions/53860939/how-to-validate-whether-my-form-is-valid-from-an-oncomplete-function-in-a-bcomm) – Selaron Nov 27 '19 at 22:08
  • Unfortunately I cannot use ```b:commandButton``` from Bootsfaces but have to use the standard component ```h:commandButton``` which does not have an ```oncomplete``` attribute. So the challenge is to emulate the Bootsfaces functionality without using ```b:commandButton```. – trane Nov 28 '19 at 08:31
  • Fortunately you can emulate the `oncomplete` event using `f:ajax onevent`: [ajax call in jsf 2.0 (myfaces), the onevent Javascript function in the ajax tag gets called before the rendering is complete](https://stackoverflow.com/questions/11350769/ajax-call-in-jsf-2-0-myfaces-the-onevent-javascript-function-in-the-ajax-tag) – Selaron Nov 28 '19 at 08:39
  • I am using ```onevent``` as you can see in the code example above. But how do I stop the Ajax request from getting actually processed? The goal is to not close the modal dialog and to not make the Ajax request in case the validation fails (field is empty). – trane Nov 28 '19 at 09:33

1 Answers1

0

It indeed looks like

<h:commandButton>
    <f:ajax onevent="function(e){if(e.status == 'complete') doSomething();}"/>
</h:commandButton>

is not the equivalent for

<b:commandButton ajax="true" oncomplete="doSomething();"/>

In order to close the modal dialog via javascript from a h:commandButton only if the form has no validation error you have to:

  1. Add the <b:fetchBeanInfos/> component to your form as suggested in this post I originally proposed as duplicate of your question. Also make sure it is updated with each ajax request.
  2. Do not check for data.status == 'complete' but instead data.status == 'success'
  3. Remove the onclick="validateModalDialog();" entirely.

Here is your code changed for server side validation closing the dialog only if the input is not empty (required="true"). Note that also testBean.save() gets invoked only for valid input.

<b:form>
    <!--  section that gets updated by ajax-request -->
    <b:panel id="updateSection">
        <h:outputText value="#{testBean.value1}" />
        <b:button value="open dialog" onclick="$('.pseudoClass').modal()" />
    </b:panel>
    <!-- modal dialog -->
    <b:modal title="model" styleClass="pseudoClass" closable="false"
        closeOnEscape="true">
        <b:panel id="modalOutput">
            <h:inputText id="myInput" value="#{testBean.value1}" required="true" />
            <h:message for="myInput" />
            <b:fetchBeanInfos /> <!-- creates the validationFailed JavaScript variable 
                                  and must be within rendered components. -->
        </b:panel>
        <f:facet name="footer">
            <!-- cancel button -->
            <b:button largeScreen="half" value="cancel" dismiss="modal"
                onclick="return false;" />
            <!-- submit button ajax-style -->
            <h:commandButton value="submit" action="#{testBean.save()}">
                <f:ajax render="updateSection modalOutput"
                    execute="@this modalOutput" onevent="closeModalDialog" />
            </h:commandButton>
            <!-- scripts to close & validate modal dialog -->
            <h:outputScript>
                   function closeModalDialog(data) {
                       var status = data.status;
                       if (!validationFailed &amp;&amp; status === 'success') { $('.pseudoClass').modal('hide'); }
                   }
           </h:outputScript>
        </f:facet>
    </b:modal>
</b:form>

A little demonstration:

enter image description here


If you want to completely block the ajax form submission on invalid form and do client side validation, you have to modify your onclick in accordance to: JSF ajax request is not fired when combined with JS client-side validation:

<h:commandButton value="submit" action="#{testBean.save()}" 
        onclick="if(!validateModalDialog()) return false;">
    <f:ajax render="updateSection" execute="@this modalOutput" onevent="closeModalDialog" />
</h:commandButton>

Beware client side validation does not prevent users from submitting invalid data by e.g. simply playing around using their browser dev tools.

Selaron
  • 6,105
  • 4
  • 31
  • 39
  • When clicking the ```commandButton``` the function ```doSomethingIfValid``` is called. But there seems to be no way to stop the Ajax request from getting fired in case validation fails. – trane Nov 28 '19 at 17:24
  • Yes, `doSomethingIfValid` is called 3 times per ajax request: on start, success and completion. That's OK. `doSomething` is invoked only if the form is valid. I don't understand what you mean by "stop the ajax request"? It does not make sense. The ajax call is required to complete in order to determine if the input is valid server side. Or do you do pure client side form validation? – Selaron Nov 28 '19 at 19:35
  • @trane I added a hint on client side validation to my post. – Selaron Nov 28 '19 at 20:14
  • Yes, I want to do the validation on the client side. Guess I did not made that clear enough in my initial post. The reason for doing it on the client side is that the validation should happen in a modal dialog. If the validation fails the dialog should not be closed. I take a closer look at your latest additions tomorrow. – trane Nov 28 '19 at 21:38
  • @trane there is no reason doing it on client side - you can do it server side via AJAX and prevent the dialog from close if there is a validation failure (javaScript variable `validationFailed` is true then thanks to `b:fetchBeanInfos` component). See my edit - I made it match your example code. – Selaron Nov 29 '19 at 07:32
  • To clarify what the solution to my problem is I updated my initial post. – trane Nov 30 '19 at 15:52