{"id":82465,"date":"2018-12-17T16:13:01","date_gmt":"2018-12-17T16:13:01","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=82465"},"modified":"2022-05-02T20:46:55","modified_gmt":"2022-05-02T20:46:55","slug":"bootstrap-4-and-self-validating-forms","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/javascript\/bootstrap-4-and-self-validating-forms\/","title":{"rendered":"Bootstrap 4 and Self-validating Forms"},"content":{"rendered":"<p>In a previous <a href=\"https:\/\/www.red-gate.com\/simple-talk\/dotnet\/net-development\/building-better-html-forms-in-vanilla-js\/\">article<\/a>, I covered the first step toward building a minimal but effective vanilla-JS framework for dealing with HTML forms. The sample framework (named <em>ybq-forms.js<\/em>) was based on only a couple of files\u2014a JavaScript file and a companion CSS file. In this article, I\u2019ll just take the code one step further adding the undo capability, field validation and Ajax posting to the server. As emphatic as it may sound, it is not much different from what you get out of the Angular ad hoc modules and from other far larger and popular frameworks. The sample pages are built using ASP.NET Core but that\u2019s not a requirement at all as the core of the solution is made of pure JavaScript and Bootstrap 4 native styles.<\/p>\n<p>A brief recap of the previous article is in order only to give a bit of context. The <code>FORM<\/code> element is decorated with a custom CSS style that has no other purpose in life than making the <code>FORM<\/code> easily selectable via code.<\/p>\n<pre class=\"lang:c# theme:vs2012\">&lt;<strong>form<\/strong> class=\"ybq-form\" action=\"...\" method=\"post\"&gt;<\/pre>\n<p>The JavaScript file bound to the host page will hook up all form elements decorated with the matching class and perform some work on contained elements.<\/p>\n<pre class=\"lang:c# theme:vs2012\">$(\".ybq-form\").each(function () {\r\n   ...\r\n});<\/pre>\n<p>In particular, the code will save to a newly created <code>data-orig<\/code> attribute the original value of each field. Original values are used to detect if the form has changed values and, in this article, will also be the foundation to enable the undo functionality. Aside from the automatic detection of pending changes and injection of some ad hoc user interface to give feedback to users, the code coming with the previous article didn\u2019t perform other significant tasks. (See figure.)<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"586\" height=\"664\" class=\"wp-image-82466\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/12\/word-image-83.png\" \/><\/p>\n<p>Let\u2019s add some more power!<\/p>\n<h2>Extending the User Interface<\/h2>\n<p>To enable the <code><em>UNDO<\/em><\/code> functionality, you need a button to click, and the framework can create one for you. Most of the graphical settings are hardcoded, but the source code is available for you to make all the changes you may desire.<\/p>\n<pre class=\"lang:c# theme:vs2012\">$(\".ybq-form\").each(function() {\r\n    \/\/ Some existing code here \r\n     ...\r\n\r\n     \/\/ Add UNDO button\r\n})<\/pre>\n<p>The <code><em>UNDO<\/em><\/code> button consists of some static markup as below.<\/p>\n<pre class=\"lang:c# theme:vs2012\">&lt;button onclick='__undo(this)' type='button' \r\n        class='btn btn-secondary'&gt;\r\n    &lt;i class='fa fa-undo'&gt;&lt;\/i&gt;\r\n&lt;\/button&gt;<\/pre>\n<p>The <code>__undo<\/code> function, instead, is a new addition to the framework. Here\u2019s the related code.<\/p>\n<pre class=\"lang:c# theme:vs2012\">function __undo(elem) {\r\n    var form = $(elem).parents('form:first');\r\n    form.find(\"input\").each(function () {\r\n        var orig = $(this).data(\"orig\");\r\n        $(this).val(orig);\r\n    });\r\n    $(elem).blur();\r\n}<\/pre>\n<p>The code loops through the input fields of the form, and for each field, it restores the value previously saved in the <code>data-orig<\/code> attribute. The figure below shows the effect of the dynamically created <em>UNDO<\/em> button.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"783\" height=\"540\" class=\"wp-image-82467\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/12\/word-image-84.png\" \/><\/p>\n<p>As you may see in the user interface, the JavaScript framework also added a submit button. It does that at the same time it adds the <em>UNDO<\/em> button. It may look like a weird behavior that a framework adds a submit button to a form. The rationale for such a choice is twofold. One reason is automating all repetitive and boilerplate tasks as much as possible and, at the same time, achieving a consistent design across all forms of the application. Second, having a control bar at the top of the form will let you wrap the rest of the form in a scrollable area of the desired height. This will guarantee that users can scroll the input fields while having the operational buttons easily reachable and visible all the time. (See Figure.)<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"420\" height=\"560\" class=\"wp-image-82468\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/12\/word-image-85.png\" \/><\/p>\n<p>To make the body of the form scrollable, you need to wrap the list of input fields with an additional DIV element of the desired fixed height.<\/p>\n<pre class=\"lang:c# theme:vs2012\">&lt;div class=\"col-12\"\r\n     style=\"height: 400px; padding: 0; overflow-y: auto;\"&gt;\r\n       &lt;!-- List of the form input fields   --&gt;  \r\n&lt;\/div&gt;<\/pre>\n<p>The next step is finding a way to automate the validation of input fields.<\/p>\n<h2>Input Field Validation<\/h2>\n<p>There are thousands of different approaches to validate the content of an input field before and after it is posted to the server. All possible solutions have pros and cons, no one is perfect, and no one is patently out of place. In the ASP.NET space, some love data annotations to unify as much as possible the validation experience on the client and the server. Also <code>jquery.validation<\/code> is fairly popular and Angular has its own components. Last but not least, vanilla JavaScript is still an option, and probably the most flexible of all and the most verbose.<\/p>\n<p>The purpose of the code discussed in this article is to keep every aspect of the code to a minimum level of complexity and a good level of abstraction. Here\u2019s an idea to write as little code and markup as possible while covering at least the most common validation scenarios.<\/p>\n<pre class=\"lang:c# theme:vs2012\">&lt;input type=\"text\" \r\n       class=\"form-control\" \r\n       id=\"username\" name=\"username\"\r\n       data-rule=\"{val}.length &gt; 0\"\r\n       placeholder=\"User name\" \r\n       value=\"Dino\" \/&gt;<\/pre>\n<p>Most of the time, validation consists in checking that a given field is not left empty, that the entered value falls in a given range of numbers or dates and that the typed text matches some patterns, such as telephone numbers, emails, and URLs. Another relatively common situation is when two or more fields must be validated together, for example, to ensure that pickup and drop-off locations of a transportation request do not match or that the new password is repeated correctly in the second input field.<\/p>\n<p>The sample <code>INPUT<\/code> element above features a custom <code>data-rule<\/code> attribute set to string expression. Although a bit cryptic, the validation rule indicates that the value of the username field is expected to not null. It goes without saying that the data rule is not executable code and that some built-in JavaScript library will take care of that. At the same time, for a developer, indicating a text-based rule is much faster than linking a distinct JavaScript file or populating some inline SCRIPT tag. The data-rule attribute doesn\u2019t handle complex validation scenarios but works just fine for simple and most common cases. On the other hand, also bear in mind that ASP.NET data annotations are not that easy to handle if you want to do cross-field validation. Have a look at how the <code>ybq-forms<\/code> library handles validation rules expressed through the <code>data-rule<\/code> attribute.<\/p>\n<p>Validation of the inline rules takes place on the <code>blur<\/code> event so that users can have immediate feedback as they tab out of each field. Note that this approach doesn\u2019t prevent you from applying some further overall client-side validation upon submission of the form. Performing validation on individual <code>blur<\/code> events also maintains the validity state of the form constantly updated. The next step, therefore, is using the valid-state information to enable or disable the submit button. Why should you ever attempt to post a form that is patently violating the rules? Have a look at the source code for <code>data-rule<\/code> processing.<\/p>\n<pre class=\"lang:c# theme:vs2012\">function __attachValidationHandler(input) {\r\n    var rule = input.data(\"rule\");\r\n    if (typeof rule !== 'undefined' &amp;&amp; rule.length &gt; 0) {\r\n        input.on(\"blur\",\r\n            function () {\r\n                var current = __getCurrentValue($(this));\r\n                var code = rule.replace(\"{val}\", \"'\" +\r\n                           current + \"'\");\r\n                var result = __eval(code);\r\n                if (result)\r\n                    $(this).removeClass(\"is-invalid\");\r\n                else\r\n                    $(this).addClass(\"is-invalid\");\r\n            });\r\n    }\r\n}<\/pre>\n<p>The previous chunk of JavaScript code attaches an <code>onblur<\/code> event handler to every input field within the form. The structure of the code is easy to figure out. If the rule expression is defined, then a handler is created for the <code>blur<\/code> event that expands the <code>{val}<\/code> placeholder of the rule to the current value of the input field and executes the expression. For example, if the username field contains <em>Dino<\/em><code>,<\/code> then the expression evaluated by the blur event is the following:<\/p>\n<pre class=\"lang:c# theme:vs2012\">\"Dino\".length &gt; 0<\/pre>\n<p>Some further explanation deserves the <code>__eval<\/code> internal function. As you may know, JavaScript features the embedded <code>eval<\/code> function whose purpose is exactly to take a string of text and treat it as if it were executable code. In other words, if the string passed to <code>eval<\/code> is made of executable code, the interpreter can understand then the code executes. This is a potential security issue especially when the code has no control over the string that could be passed. The following code is a more secure way to execute dynamic JavaScript code.<\/p>\n<pre class=\"lang:c# theme:vs2012\">function __eval(code) {\r\n    return Function('\"use strict\";return (' + code + ')')();\r\n}<\/pre>\n<p>The next problem to face is how to let users know about the outcome of the validation. If the validation succeeded, there might be no need to show anything (some forms, however, presents a nice green checkmark to confirm). For sure, instead, there will be the need to show feedback if the validation fails. Here\u2019s where Bootstrap 4 makes the difference.<\/p>\n<pre class=\"lang:c# theme:vs2012\">var result = __eval(code);\r\nif (result)\r\n    $(this).removeClass(\"is-invalid\");\r\nelse\r\n    $(this).addClass(\"is-invalid\"); <\/pre>\n<p>By simply adding to the input field the new style <code>is-invalid<\/code> (or <code>is-valid<\/code>) you instruct the Bootstrap library to visually mark the control with a red border. Also, if you have a sibling <code>DIV<\/code> marked with the class invalid-feedback, then that content is automatically displayed. (See figure.)<\/p>\n<pre class=\"lang:c# theme:vs2012\">&lt;div class=\"form-group\"&gt;\r\n    &lt;label for=\"username\"&gt;Username&lt;\/label&gt;\r\n    &lt;input type=\"text\" class=\"form-control\" \r\n           id=\"username\" name=\"username\"\r\n           data-rule=\"{val&gt;}.length &gt; 0\"\r\n           placeholder=\"User name\" value=\"Dino\"&gt;\r\n    &lt;div class=\"invalid-feedback\"&gt;\r\n        Name is a required field\r\n    &lt;\/div&gt;\r\n&lt;\/div&gt;<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"426\" height=\"562\" class=\"wp-image-82469\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/12\/word-image-86.png\" \/><\/p>\n<p>To clear the visual state of the element, it is sufficient that you remove the is-invalid CSS class programmatically. If you intend to confirm that the value typed is acceptable, you can also have a <code>DIV<\/code> flagged with the <code>valid-feedback<\/code> CSS style.<\/p>\n<h2>Submitting the Form<\/h2>\n<p>The final step is automating the upload of the form to the extent that it is possible. The JavaScript library that comes with the article adds a free submit button and gives it a standard CSS class that makes it easier to hide or delete it programmatically. The button doesn\u2019t have any click handler but, being a submit button, it triggers a form-level <code>submit<\/code> event. The library adds a default submit handler.<\/p>\n<pre class=\"lang:c# theme:vs2012\">form.on(\"submit\",\r\n    function () {\r\n        var valid = (form.find(\"input.is-invalid\").length === 0);\r\n        if (!valid) {\r\n           return false;\r\n        }\r\n        var formData = new FormData(form);\r\n        $.ajax({\r\n            cache: false,\r\n            url: form.attr(\"action\"),\r\n            type: form.attr(\"method\"),\r\n            dataType: \"html\",\r\n            data: formData,\r\n            success: function (data) {\r\n                (__eval(successCallback))(data);\r\n            },\r\n            error: function (data) {\r\n                (__eval(errorCallback))(data);\r\n            }\r\n        });\r\n        return false;\r\n    });<\/pre>\n<p>As you can see, the code uses Ajax and jQuery to post the content of the form to the server. Debugging any ASP.NET server-side code works as expected and, at the end of the day, the library saves you a lot of boilerplate code. The only exception is the behavior expected once the content of the form has been processed on the server. This code is specific of each form and can hardly be automated and generalized by any framework.<\/p>\n<pre class=\"lang:c# theme:vs2012\">&lt;<strong>form<\/strong> action=\"\/demo\/form2\" method=\"post\" \r\n     class=\"ybq-form\" \r\n     data-successcallback=\"__successForm\" \r\n     data-errorcallback=\"__errorForm\"&gt;\r\n...\r\n&lt;<strong>\/form<\/strong>&gt;<\/pre>\n<p>By adding a couple of ad hoc attributes, however, you can limit the writing of this handling code to the absolute minimum. The <code>data-successcallback<\/code> attribute points to the name of the JavaScript that will handle the success of the submission. The <code>data-errorcallback<\/code> attribute, instead, takes the name of the function to invoke in case of a status code different from 200. As in the code snippet above, the <code>__eval <\/code>helper function is used again to transform a plain string into runnable JavaScript code. The view that defines the form can handle the post form operation as below.<\/p>\n<pre class=\"lang:c# theme:vs2012\">&lt;script&gt;\r\n    function __successForm(data) {\r\n        alert(\"RESULT IS: \" + data);\r\n    }\r\n&lt;\/script&gt;\r\n&lt;script&gt;\r\n    function __errorForm(data) {\r\n        alert(\"DIDN'T WORK\");\r\n    }\r\n&lt;\/script&gt;<\/pre>\n<p>The success callback function receives the value returned by the controller method; the error callback function, instead, takes a value that refers to the exception occurred. Finally, if you need to do some form-wide, cross-field validation, you can add your own submit button and do your checks.<\/p>\n<pre class=\"lang:c# theme:vs2012\">&lt;script&gt;\r\n    $(\"#submitBtn\").click(function() {\r\n        if ($(\"#password\").val().length &lt; 5) {\r\n            $(\"#password\").addClass(\"is-invalid\");\r\n            return false;\r\n        }\r\n    });\r\n&lt;\/script&gt;<\/pre>\n<p>Alternatively, if you don\u2019t want to have an additional submit button then you can hook up the form\u2019s submit event and perform the script-based validation.<\/p>\n<h2>Summary<\/h2>\n<p>The purpose of this article and the previous on automatic management of HTML forms was to significantly minimize the amount of code to be written for such a common task like posting a form. Validation, detection of changes, submission and display of feedback are all tasks that can be largely automated. Angular, for example, does just that. Now you have a starting point for a lightweight vanilla-JS library. The full source of <em>ybq-forms<\/em> can be found at <a href=\"https:\/\/bit.ly\/2znGhVP\">https:\/\/bit.ly\/2znGhVP<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Validating the user input of a web form is important for security and data quality. In this article, Dino Esposito explains how to validate a form and add undo capability with Bootstrap 4.&hellip;<\/p>\n","protected":false},"author":221911,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[146044],"tags":[95509],"coauthors":[6780],"class_list":["post-82465","post","type-post","status-publish","format-standard","hentry","category-javascript","tag-standardize"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/82465","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221911"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=82465"}],"version-history":[{"count":3,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/82465\/revisions"}],"predecessor-version":[{"id":94019,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/82465\/revisions\/94019"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=82465"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=82465"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=82465"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=82465"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}