{% 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 %}

Introduction - Single field

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...

{{validation['demoForm.email'] | validationMessages()}}
You can display (or hide) some elements/sections depending on the validation status of a field or of the form itself. For example :
{% if validation._ | validationFresh() %}
Fresh
This <div> is only displayed when the form has not been submitted yet (we say the form is "fresh"). This can be validated using the "_" element, which represents the form itself (more info) : {% verbatim %}{% if validation._ | validationFresh() %}{% endverbatim %}
{% endif %} {% if validation._ | validationSubmitted() and validation['demoForm.email'] | validationIsValid() %}
Valid
This <div> is displayed because the form has been submitted and the field is valid. You often need to validate that the form has been submitted in addition to validate if a field is valid because, when a field is displayed for the first time, it doesn't contain any errors so it is considered as being "valid". You can validate that the form has been submitted using the "_" element, which represents the form itself (more info) : {% verbatim %}{% if validation._ | validationSubmitted() and validation['demoForm.email'] | validationIsValid() %}{% endverbatim %}
{% endif %} {% if validation['demoForm.email'] | validationHasSuccesses() %}
Success
This <div> is displayed because the following condition is true : {% verbatim %}{% if validation.demoForm['demoForm.email'] | validationHasSuccesses() %}{% endverbatim %}
{% endif %} {% if validation['demoForm.email'] | validationHasWarnings() %}
Warning
This <div> is displayed because the following condition is true : {% verbatim %}{% if validation['demoForm.email'] | validationHasWarnings() %}{% endverbatim %}
{% endif %} {% if validation['demoForm.email'] | validationHasErrors() %}
Error
This <div> is displayed because the following condition is true : {% verbatim %}{% if validation['demoForm.email'] | validationHasErrors() %}{% endverbatim %}
{% endif %}
Validations to test :
  • 1. If the email is valid, we redirect to a new page with a Flash Message. This is a commonly used pattern when a form is valid : the user is redirected to a confirmation page so a "refresh" of the page won't send the POST data again. Fill form
  • 2. If the email is "stay@example.com", the field is valid but we do not redirect to a new page. This is to demonstrate that you can redisplay a form even if all the fields are valid. Fill form
  • 3. If the email is "success@example.com", we do not redirect to a new page and we display a Success Validation Message for the field. Fill form
  • 4. If the email is shorter than 8 characters ("a@b.ca" for example), we display a Warning Validation Message. Notice that the form doesn't become red since a warning is not an error, it doesn't make the form invalid! Fill form
  • 5. If the field is empty, or if it only contains spaces, an Error Validation Message is displayed. The form is invalid and becomes red... Empty form
  • 6. If the email is invalid, an Error Validation Message is displayed. The form is invalid and becomes red... Fill form
  • 7. If the email is "all@example.com" with display three Validation Messages, one for each level : Success, Warning and Error. This is to demonstate that a field can have multiple Validation Messages associated with it. Fill form

Code

How to

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('')}}">

{% endverbatim %} You can learn in the Getting the submitted form data section of the document that Spincast uses the names of the fields to build a JsonObject representing the submitted form. This is why we are able to access a parent element named "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 :

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>

{% endverbatim %}

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.

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>&lt;div&gt;</code> is displayed because the following condition is true :
         {% verbatim %}<code class="snippet">{% if validation['demoForm.email'] | validationHasWarnings() %}</code>{% endverbatim %}
     </div>
 {% endif %}

{% endverbatim %}

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>

{% endverbatim %}

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

{% endverbatim %}

is much better than : {% verbatim %}


{{validation['email'] | validationMessages()}}

{% endverbatim %} since the name of the input field is "demoForm.email"...

You can learn more about this topic in the Validation Keys section!

More info

Learn everything about validation and forms in their dedicated Validation and Forms sections of the documentation.

{% endblock %}