Please note :
Validation Messages
can be displayed.
In this demo, we're going to look at more complex validation, where many different types of fields are validated, and where the validity of some fields depends on the value of other fields.
Enter any valid or invalid values in the following form and submit it to see the validation in action!
You can also try the tests suggested on the right...
HTML
template (the frontend part) :
multiple.html
We already introduced the process of validating a form in the Introduction demo. In this one, we focus mostly on how to display the various types of fields, how to validate a field by comparing its value with another field, and how to run conditional validations.
Let's first examine how we render the fields in the
HTML
template, and how we use Validation Filters
for the validation messages
...
The "email"
and "emailAgain"
are simple text inputs.
Here's the "email"
field :
<input type="text" class="form-control" id="email" name="demoForm.email" placeholder="Email" value="{{demoForm.email | default('')}}" /> {{validation['demoForm.email'] | validationMessages()}}We use
"{{demoForm.email | default('')}}"
to
fill the inital value [3] and "{{validation['demoForm.email'] | validationMessages()}}"
to display the potential Validation Messages
[4].
The tags
section is more interesting :
<div class="col-sm-2 fieldGroupLabelAndMessages"> <label class="control-label">Tags *</label> {{validation['demoForm.tags'] | validationGroupMessages()}} </div> <div class="col-sm-4"> <input type="text" class="form-control {{validation['demoForm.tags[0]'] | validationClass()}}" id="tag1" name="demoForm.tags[0]" placeholder="Tag 1" value="{{demoForm.tags[0] | default('')}}" /> {{validation['demoForm.tags[0]'] | validationMessages()}} <input type="text" class="form-control {{validation['demoForm.tags[1]'] | validationClass()}}" id="tag2" name="demoForm.tags[1]" placeholder="Tag 2" value="{{demoForm.tags[1] | default('')}}" /> {{validation['demoForm.tags[1]'] | validationMessages()}} <input type="text" class="form-control {{validation['demoForm.tags[2]'] | validationClass()}}" id="tag3" name="demoForm.tags[2]" placeholder="Tag 3" value="{{demoForm.tags[2] | default('')}}" /> {{validation['demoForm.tags[2]'] | validationMessages()}} </div>
Those fields form a group. We can know this by looking at their
"name"
attributes : "demoForm.tags[0]"
,
"demoForm.tags[1]"
and "demoForm.tags[2]"
. This syntax
indicates that those fields are part of the same group and have a specific position in it.
At the top of this code snippet, you can see that there is section which
describe the section those fields are in : "Tags *"
. We
use this zone to output the Validation Messages
associated with the
group itself :
{{validation['demoForm.tags'] | validationGroupMessages()}}
"tag"
field is invalid, this filter will display an
error : "Some tags are invalid."
. This error is not associated
with a particular field, but with the group itself.
Next, we have the "Favorite drink"
radio buttons group.
In this section too we have
a zone where some Validation Messages
may be displayed for the group itself :
<div class="col-sm-2 fieldGroupLabelAndMessages"> <label class="control-label">Favorite drink *</label> {{validation['demoForm.drink'] | validationGroupMessages()}} </div>
Otherwise, every radio button of the group is listed using a code similar to this :
<div class="radio"> <label for="drink0"> <input type="radio" id="drink0" name="demoForm.drink" {{demoForm.drink | checked("tea")}} value="tea" /> Tea</label> </div> <div class="radio"> <label for="drink1"> <input type="radio" id="drink1" name="demoForm.drink" {{demoForm.drink | checked("coffee")}} value="coffee" /> Coffee</label> </div> //...
Explanation :
"name"
attribute! Not only does this
make the fields being a group in the eyes of the browser (only one radio button
of this group can be checked at a given time), but it also tells Spincast that those
radio buttons are part of the same group.
checked(...)
filter to determine if a radio button must be checked or not. Learn
more about this filter in the Provided functions and filters
section.
The "Pick 2 numbers *"
section allows more than one option to be picked, so
checkboxes are used :
<div class="checkbox"> <label for="num1"> <input type="checkbox" id="num1" name="demoForm.numbers[0]" {{demoForm.numbers[0] | checked("1")}} value="1" /> 1</label> </div> <div class="checkbox"> <label for="num2"> <input type="checkbox" id="num2" name="demoForm.numbers[1]" {{demoForm.numbers[1] | checked("2")}} value="2" /> 2</label> </div> //...
Those checkboxes are part of the same group, so we want to receive them as an array
when the form is submitted. For that reason,
it's recommended to use brakets ("[]"
) at the end of their "name"
attributes and, when possible, to specify the position of the element inside those brackets.
As for the "drink"
radio buttons fields,
we use the checked(...)
filter to determine if an option must be checked
or not.
Finally, the "Favourite music styles?"
and the "Action on submit"
are both <select>
fields. The first one, "musicStyles"
,
allow multiple options to be selected :
<select multiple id="musicStyles" name="demoForm.musicStyles[]" class="form-control"> <option value="rock" {{demoForm.musicStyles | selected("rock")}}>Rock</option> <option value="pop" {{demoForm.musicStyles | selected("pop")}}>Pop</option> <option value="jazz" {{demoForm.musicStyles | selected("jazz")}}>Jazz</option> <option value="metal" {{demoForm.musicStyles | selected("metal")}}>Metal</option> <option value="classical" {{demoForm.musicStyles | selected("classical")}}>Classical</option> </select>
Since more than one option can be selected, we make the "name"
attribute of this
field end with "[]"
. That way, the selected options are always going to be grouped
together as an array when the form is submitted.
Note that with <select>
fields, we use the selected(...)
filter to determine if an option must be selected or not. This filter is going to output a "selected"
attribute, where required.
The last thing on the frontend we'll going to have a look at is how to display the status of the form itself. Notice that we display a message at the top of the form to show if it is valid or not :
{% if validation['demoForm._'] | validationSubmitted()%} {% if validation['demoForm._'] | validationHasErrors() %} {% set alertClass = "alert-danger" %} {% set status = "contains errors" %} {% elseif validation['demoForm._'] | validationHasWarnings() %} {% set alertClass = "alert-warning" %} {% set status = "contains warnings" %} {% elseif validation['demoForm._'] | validationIsValid() %} {% set alertClass = "alert-success" %} {% set status = "is valid" %} {% endif %} <div class="row"> <div class="col-sm-6"> <div class="alert {{alertClass}}"> <img src="/public/images/icons/info2.png" /> The Form <strong>{{status}}</strong> </div> </div> </div> {% endif %}
Explanation :
"_"
element is a special element which
represents a Validation Set
itself.
validationHasErrors()
filter [4],
the validationHasWarnings()
filter [8] and
the validationIsValid()
filter [12] to
pick the appropriate CSS
class and status to use for the message we're going to
display.
CSS
class.
On the backend, this demo shows how to run a validation or not depending on the result of a previous validation. For example :
String email = form.getString("email"); if (StringUtils.isBlank(email)) { form.addError("email", "email_empty", "The email is required"); } if (form.isValid("email") && !form.validators().isEmailValid(email)) { form.addError("email", "email_invalid", "The email is invalid"); }
As you can see, we only perform the second validation if the first one is a success! This is often very useful since we do not want to display multiple error messages for a single field when, in fact, the field was simply left empty.
In this demo, we also see how to validate a field by comparing it's value to the value of another field. For example :
String email = form.getString("email"); // ... String emailAgain = form.getString("emailAgain"); // ... if (form.isValid("emailAgain") && !emailAgain.equals(email)) { form.addError("emailAgain", "emailAgain_mustMatch", "Must match the first email field."); }
There are more validations performed in this demo! We suggest you have a look at DemoHtmlFormsMultipleFieldsController code to see all of them.
Make sure you also try the first demo of this section, Introduction - Single field which introduces forms and validation using Spincast.
Otherwise, you can learn everything about forms and validation in the dedicated Forms section of the documentation.