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>
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:
<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.data.status == 'complete'
but instead data.status == 'success'
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 && status === 'success') { $('.pseudoClass').modal('hide'); }
}
</h:outputScript>
</f:facet>
</b:modal>
</b:form>
A little demonstration:
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.