{% extends "../htmlForms.html" %} {% block demoSectionClasses %}demo_html_forms_single{% endblock %} {% block meta_title %}Demos - HTML Forms - Introduction{% endblock %} {% block meta_description %}HTML Forms and validation demo - introduction{% endblock %} {% set demoId = "single" %} {% block scripts %} {% endblock %} {% block demoBody %}
Please note :
Enter any valid or invalid input in the following field and submit the form to see the validations in action!
You can also try the tests suggested on the right...
HTML template (the frontend part) :
single.html
The purpose of this demo is to introduce you to the validation of HTML forms using Spincast and to demonstrate how you can use the various Validation Filters. Depending on the value of the "email" field, the controller may add Validation Messages to the response and then redisplay the form, or may redirect you to a confirmation page.
First notice that, in our HTML form, the "name" attribute of the email field is "demoForm.email" :
{% verbatim %}
<input type="text"
class="form-control"
id="email"
name="demoForm.email"
placeholder="Email"
value="{{demoForm.email | default('')}}">
"demoForm" on the
submitted form data :
public void singleFieldSubmit(AppRequestContext context) {
JsonObject form = context.request().getFormData().getJsonObject("demoForm");
//...
Note that we could also have retrieved the email field directly, using its full
"demoForm.email" JsonPath :
String email = context.request().getFormData().getString("demoForm.email");
But, in general, a form contains more than one field and using such "parent element" allows you to validate them together.
Now that we have the form parent element, we are going to validate it. To do so
we first have to create a Validation Set. Since
the form object is a JsonObject, we simply have to use its
validationSet() method :
// We get a Validation Set instance to start the validation of // our form JsonObjectValidationSet validationSet = form.validationSet();
We use this Validation Set to perform any validation we need on the object. Let's see the
first validation used in this demo, where we verify that the submitted email is not blank :
ValidationSet lastResult = validationSet.validationNotBlank()
.jsonPath("email")
.failMessageText("The email is required")
.validate();
Notice that we use "email" as the JsonPath to target the
element we want to validate [3]. Since the form object
is the root element we started the validation on,
we have to use a JsonPath relative to it.
The validationNotBlank() method is a predefined validation. There
are many of them available on a Validation Set object.
When run, a predefine validation results in two things :
Validation Set (a "The email is required" error message, for example).
Validation Set is returned (This set is named "lastResult" in our example).
The set returned by a predefined validation contains the results of this particular validation.
By using those standalone sets returned by validations, you are able to perform a validation or not
depending on the result of a previous validation!
When our validation is done, we check if our initial Validation Set contains any
error and, if so, we redisplay the form with its associated Validation Messages.
To do so, we add the form object to the response model
using the same "demoForm" key we used to retrieve it. We also add our
Validation Set to the response model, so the Validation Messages are
available and can be displayed in our HTML template :
// Are there some errors?
if(!validationSet.isValid()) {
// Adds the form to the response model
context.response().getModel().put("demoForm", form);
// Adds the Validation Set to the response model.
context.response().getModel().put("validation", validationSet);
// Sends the template
sendTemplate(context);
} else {
//...
}
Note that the actual code of this demo is slightly different, simply because we wanted to show that a form can be redisplayed even if it is valid. But, most of the time, you're not going to do this... In fact, if the form is valid, you want to redirect the user to a confirmation page, using a Flash message :
if(!validationSet.isValid()) {
//...
} else {
// No errors! We process the form data, using
// services, data sources, etc.
// ...
// And then we redirect to a confirmation page
context.response().redirect(FlashMessageLevel.SUCCESS,
"the form has been processed successfully.");
}
The last step of the validation process is to
redisplay the form with the resulting Validation Messages, in your template.
To help you, Validation Filters are provided : {% verbatim %}
<div class="form-group {{validation['demoForm.email'] | validationClass()}}">
<label for="email" class="col-sm-4 control-label">Email *</label>
<div class="col-sm-8">
<input type="text"
class="form-control"
id="email"
name="demoForm.email"
placeholder="Email"
value="{{demoForm.email | default('')}}">
{{validation['demoForm.email'] | validationMessages()}}
<div class="validationsDirectBtnDiv">
<button id="subBtn" type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</div>
Since we added the Validation Set to the response model, our template has access
to its messages through the "validation" element. From this element, we get the Validation Messages associated
with our field using the "demoForm.email" validation key
and we pass the result to the validationClass() and validationMessages()
filters.
validationClass() filter outputs an appropriate CSS class name,
depending on the result of the validation.
validationMessages() filter format and output the
Validation Messages themselves. The template fragment used is
of course configurable.
Notice that we also use the default() filter which is provided by
Pebble out of the box : {% verbatim %}{{demoForm.email | default('')}}{% endverbatim %}.
This will fill the email field with the submitted value,
or will fallback to an empty string if that value doesn't exist on the model.
The last thing we also demonstrate in this demo is how to display some HTML elements/sections or not, depending on
the result of the validation. For example, using the validationHasWarnings() filter,
we check if the email contains Warning Validation Messages and, if so, we display a special
<div> element :
{% verbatim %}
{% if validation['demoForm.email'] | validationHasWarnings() %}
<div class="well niceWell warning">
<div class="niceWellTitle">Warning</div>
This <code><div></code> is displayed because the following condition is true :
{% verbatim %}<code class="snippet">{% if validation['demoForm.email'] | validationHasWarnings() %}</code>{% endverbatim %}
</div>
{% endif %}
Make sure you read the Validation Filters section of the documentation to see what are the filters related to validation, and how to use them!
One last thing! Let's go back server-side for a minute... You may have noticed in the
code
that, when the Validation Set is ready, we prefix its validation keys with the string "demoForm."
before we actually use it :
JsonObject form = context.request().getFormData().getJsonObject("demoForm");
ValidationSet validationSet = validateForm(form).prefixValidationKeys("demoForm.");
// ... uses the Validation Set
Why are we doing this?
Since we call the validateForm(...) method with "form" as the object to validate, the validations
are performed relatively to this object, so "email" is used as the validation keys to store the
Validation Messages for this element. But, in our final Validation Set, we would like
the validation keys to reflect the JsonPaths
of their associated element. If we were not to prefix the validation keys with "demoForm.",
the template of the "email" field would look like this :
{% verbatim %}
<div class="form-group {{validation['email'] | validationClass()}}">
<label for="email" class="col-sm-4 control-label">Email *</label>
<div class="col-sm-8">
<input type="text"
class="form-control"
id="email"
name="demoForm.email"
placeholder="Email"
value="{{demoForm.email | default('')}}">
{{validation['email'] | validationMessages()}}
<div class="validationsDirectBtnDiv">
<button id="subBtn" type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</div>
This would have work (and you can do it if you want), but we think it's way clearer when the validation keys are actually the string representation of the JsonPaths of the elements they are associated with. We think that : {% verbatim %}
{{validation['demoForm.email'] | validationMessages()}}
is much better than : {% verbatim %}
{{validation['email'] | validationMessages()}}
input field is "demoForm.email"...
You can learn more about this topic in the
Validation Keys section!
Learn everything about validation and forms in their dedicated Validation and Forms sections of the documentation.
{% endblock %}