Simple Spring Boot CRUD application with Client-side form validation

Published by Alexander Braun on 16 Dec 2017 - tagged with Spring, Spring Boot, Bootstrap, Thymeleaf

This post describes how to add client-side form validation to an existing Spring Boot web application. The example code uses Thymeleaf Template Engine, Bootstrap 3 and Spring JPA in conjunction with HSQL DB.

Introduction

The example code is based on the previous post that described how to set up simple Spring Boot CRUD application.

This time we add client-side form validation to the existing web application. As we already use jQuery in the context of Bootstrap 3, we are going to add the jQuery validation plugin, which can be downloaded from here. Additionally, we are going to customize the plugin to support the way Bootstrap displays form errors.

Validation Rules

The existing application already allows you to to create, read, update and delete notes. The notes object consists of the following attributes:

  • id: the unique id of a notes object
  • title: the title of the notes (required, minimum length 5 and maximum length 100 characters)
  • content: the actual content of the notes (required, minimum length 8 and maximum length 10,000 characters)

Where is the code?

The code for this post is available in this GitHub repository

Implementation

Edit View: add the validation rules

First, we have to add the following two additional JavaScript files:

  • jquery.validate.min.js: the validation plugin
  • jquery.validate.bootstrap.js: the validation plugin extension to support Bootstrap (described in the next section)

To activate the form validation in the next step we have to ensure to add an id to the form element.id="notesForm" This allows us to easily select the correct form HTML element and to attach validation.

Finally, we add a JavaScript block to define the rules, custom messaged and activate validation.

It usually is a good idea to wrap the code into a $(document).ready(function () { ... } block to ensure that the document has been fully loaded before referencing elements on the page.

We activate validation for our form using.$("#notesForm").validate( options ) The options object includes two main areas:

Rules

We are going to specify all validation rules using a JSON object. This is quite easy and self-explaining. We only have to use the id of the form input element and add the validation rules. The example below shows the validation rules, based on our requirements described in the first section.

rules: {
  'title': {
	 required: true,
	 minlength: 5,
	 maxlength: 100
  },
  'content': {
	 required: true,
	 minlength: 8,
	 maxlength: 10000
  }
}

Optional: Custom messages

The validation plugin provides for all validation rules default messages, even for different languages if you include the corresponding localization files. We want to add a custom message for the required rule of the title element. It is the same idea as for the rules specification. We only have to use the form input element as a key and add the messages for each validation rule we want to customize.

messages: {
	title: {
	  required: "Please enter the title!"
  }
}

The final HTML file that includes all required changes is below.

NotesEdit.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>Notes</title>

    <link rel="stylesheet" type="text/css" media="all" href="../../css/bootstrap.min.css" th:href="@{/css/bootstrap.min.css}" />

    <script type="text/javascript" th:src="@{/js/jquery.min.js}" src="js/jquery.min.js"></script>
    <script type="text/javascript" th:src="@{/js/bootstrap.min.js}" src="js/bootstrap.min.js"></script>
    <!-- include the jQuery validation plugin -->
    <script type="text/javascript" th:src="@{/js/jquery.validate.min.js}" src="js/jquery.validate.min.js"></script>
    <!-- add the required customizations for Bootstrap -->
    <script type="text/javascript" th:src="@{/js/jquery.validate.bootstrap.js}" src="js/jquery.validate.bootstrap.js"></script>
</head>
<body>
    <div class="container">

        <h1>Notes</h1>

        <form id="notesForm" class="form-group" action="/notesEdit" th:action="@{/notesEdit}" method="post">
            <input th:type="hidden" name="id" th:field="${notes.id}" />
            <div class="form-group">
                <label for="title">Title</label>
                <input type="text" class="form-control" id="title" th:field="${notes.title}" />
            </div>
            <div class="form-group">
                <label for="content">Content</label>
                <textarea class="form-control" id="content" th:field="${notes.content}"></textarea>
            </div>
            <button type="submit" class="btn btn-primary">Save</button>
            <a href="#" th:href="@{/}" class="btn btn-danger" role="button">Cancel</a>
        </form>

    </div>

	<!-- define validation rules and activate validation -->
    <script>
         $(document).ready(function () {
             $("#notesForm").validate({
                 rules: {
                     'title': {
                         required: true,
                         minlength: 5,
                         maxlength: 100
                     },
                     'content': {
                         required: true,
                         minlength: 8,
                         maxlength: 10000
                     }
                 },
                 messages: {
                	 title: {
                         required: "Please enter the title!"
                     }
                 }
             });
         });
    </script>

</body>
</html>

Customize jQuery validation plugin

The jQuery validation plugin is a UI framework neutral solution to validate HTML forms. As we use Bootstrap for the user interface, we want to use Bootstrap's look and feel for validation and error handling as well. We can achieve this by customizing the jQuery plugin.

The solution below was introduced in this Stackoverflow post.

The basic idea is to overwrite the following methods from the validation plugin:

  • highlight: Is being invoked when a validation error was discovered for a specific form input element. We simply add the "has-error" class and remove the "has-success" class.
  • unhighlight: Is being invoked when a no validation error was discovered for a specific form input element.
  • errorPlacement: Specifies how and where to place the error text for each form input element.

jquery.validate.bootstrap.js

jQuery.validator.setDefaults({
    errorElement: "span",
    errorClass: "help-block",

    // Style the HTML element in case of validation errors
    highlight: function (element, errorClass, validClass) {
        if (!$(element).hasClass('novalidation')) {
            $(element).closest('.form-group').removeClass('has-success').addClass('has-error');
        }
    },

    // Style the HTML element in case of validation success
    unhighlight: function (element, errorClass, validClass) {
        if (!$(element).hasClass('novalidation')) {
            $(element).closest('.form-group').removeClass('has-error').addClass('has-success');
        }
    },

    // Place the error text for different input element types
    errorPlacement: function (error, element) {
        if (element.parent('.input-group').length) {
            error.insertAfter(element.parent());
        }
        else if (element.prop('type') === 'radio' && element.parent('.radio-inline').length) {
            error.insertAfter(element.parent().parent());
        }
        else if (element.prop('type') === 'checkbox' || element.prop('type') === 'radio') {
            error.appendTo(element.parent().parent());
        }
        else {
            error.insertAfter(element);
        }
    }
});
// Reference: https://stackoverflow.com/questions/18754020/bootstrap-3-with-jquery-validation-plugin

Start and test the application

We can now start the application either from the IDE or from the command line.

Command Line

We can use

mvn package

to build the application from the command line and

java -jar target/CrudClientValidationApp-1.0-SNAPSHOT.jar

to start the application.

Test the application

After starting up we can access the application using this URL: localhost:8090

The screenshot below show how the form looks like when validation errors occur.

client-side validation

Summary

Implementing client-side server validation using jQuery validation plugin with minor customization provides an easy way to improve the user experience by providing fast feedback on validation error without the requirement to go through a server round-trip.

Code on GitHub

The code for this example is available in this GitHub repository