Tuesday, July 21, 2020

Validate dynamic form fields in Thymeleaf templates

How to validate the unknown  number of input fields dynamically generated and  attached to Thymeleaf scripts
   We have to write JavaScript validations for each field in the input form if we don't use a framework such as AngularJS. The jQuery validator script makes it easy that we can add it into the script and write small snippets for the validations. It is also flexible to use with the Thymeleaf scripts since the fields are validated by the HTML identifiers. The issue is, how to validate an unknown number of fields that are dynamically generated by a thyme script array. Thymeleaf allows us to give identifiers to the fields with the indexes of the array. Therefore, we can validate them if we can loop through the fields inside the validation script. Also, We can validate the fields individually or verify the sum of the fields equal to another field, not in the array.

  As usual, we must include the jQuery validator script in the Thymeleaf template. It can be included from a local server or a CDN.
<!--Validation framework on jQuery-->
<script th:src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.2/jquery.validate.min.js">
</script>
  There are so many tailored validation methods included in the jQuery validation script. We add our custom methods to the validation script using addMethod to the jQuery validator object.

  Let's say, we have some chickens in a basket and their weights are attached to a form of fields. There is another field, 'totalWeight' to take the sum of the chicken weights, in the basket. A sample custom validation method added is shown below.
chickens - chicken array, Thymeleaf object.
<script>
       jQuery.validator.addMethod(
        "chickensWeightValidator",        // name of the validator to call within HTML input fields
        function(given_weight, element) {
            var cal_total = 0;
           
            /*<![CDATA[*/
            /*[# th:each="chicken, index : ${response?.data?.chickens}"]*/
                var weightX = parseInt($(/*[[|#chicken_${index.index}|]]*/).val());
                if(!isNaN(weightX)) cal_total = cal_total + weightX;
            /*[/]*/
            /*]]>*/
           
            var is_valid_total = (cal_total==0 || cal_total==given_weight);    // initilally cal_total=0
            return this.optional(element) || is_valid_total;
        },
        "Total weight must be equal to the sum of the chicken weights"        // a warning message if invalid
    );
</script>
  ThymeLeaf loop code is commented inside the JS but Java template engine is intelligent enough to process it and respond with pure JS code to the client requested the page.

  We can attach the validator method to the total_weight field either directly in the HTML as a class or using jQuery validate method in script separately. The latter method let us define custom highlighting methods if input value is invalid.
<form id="chickenForm" >
    <div class="invalid-feedback"></div>
    <input type="text" id="totalWeight" name="Total Weight" class="chickensWeightValidator" />
</form>
or
<script>
    $(function() {
        $("#chickenForm").validate({
            rules: {
                totalWeight:{
                    required:true,
                    chickensWeightValidator: true
                },
            },
            submitHandler: function(form) {
                form.submit(function() {
                    return true;
                });
            },
            highlight: function (element) {
                $(element).removeClass("is-valid");
                $(element).addClass("is-invalid");
            },
            unhighlight: function (element) {
                if (invalidFixed == true){
                    $(element).removeClass("is-invalid");
                    $(element).addClass("is-valid");
                }
            },
            errorElement: 'div',
            errorClass: 'invalid-feedback'
        });
    });
</script>
  That is not end there. We must validate each chicken's weight is valid. It can be done easily with min="0" tag in the HTML weight input field that is looped through the array by Thymeleaf.
<div th:each="chicken , index: ${response?.data?.chickens}">
    <input    th:id="|chicken_[__${index.index}__]|"
            th:name="|chicken_[__${index.index}__]|"
            th:value="${chicken.weight}"
            type="number"
            min = "0"
    />
</div>
or
by adding following custom validator method,
jQuery.validator.addMethod(
    "nonZeroWeight",
    function(weight, element) {
        var isValidWeight = /^[0-9]*(\.\d{0,2})?$/.test(weight) && parseFloat(weight)!=0;
        return this.optional(element) || isValidWeight;
    },
    "Enter a valid weight"
);
I have tried in several ways but could not find a way to attach the above method to the unknown number of, dynamically generated fields using the validate method in the jQuery validator. Finally, I added the method to the HTML field directly as a CSS class.

Thanks for reading!
Please share if you find it useful!
Subscribe with your email to receive New updates

No comments:

Post a Comment

Whats New

How redundant uploads can be avoided in social media apps?

People spend more time on social media, and it influences the most and changes to societies. They want to share photos and videos often when...

You may also like to read

x

emailSubscribe to our mailing list to get the updates to your email inbox...

Delivered by FeedBurner