Welcome Folks I am back with another blog post.In this post we will be learning about a new Library called as Parsley which is a Javascript form Validation Library. It has all the validations that is required for forms. In this post we will be seeing examples of this library. Let’s get started.

Simple Demo Form to Showcase Validation of Various Inputs in the Form

<div class="bs-callout bs-callout-warning hidden"> <h4>Oh snap!</h4> <p>This form seems to be invalid :(</p> </div> <div class="bs-callout bs-callout-info hidden"> <h4>Yay!</h4> <p>Everything seems to be ok :)</p> </div> <form id="demo-form" data-parsley-validate=""> <label for="fullname">Full Name * :</label> <input type="text" class="form-control" name="fullname" required=""> <label for="email">Email * :</label> <input type="email" class="form-control" name="email" data-parsley-trigger="change" required=""> <label for="contactMethod">Preferred Contact Method *:</label> <p> Email: <input type="radio" name="contactMethod" id="contactMethodEmail" value="Email" required=""> Phone: <input type="radio" name="contactMethod" id="contactMethodPhone" value="Phone"> </p> <label for="hobbies">Hobbies (Optional, but 2 minimum):</label> <p> Skiing <input type="checkbox" name="hobbies[]" id="hobby1" value="ski" data-parsley-mincheck="2"><br> Running <input type="checkbox" name="hobbies[]" id="hobby2" value="run"><br> Eating <input type="checkbox" name="hobbies[]" id="hobby3" value="eat"><br> Sleeping <input type="checkbox" name="hobbies[]" id="hobby4" value="sleep"><br> Reading <input type="checkbox" name="hobbies[]" id="hobby5" value="read"><br> Coding <input type="checkbox" name="hobbies[]" id="hobby6" value="code"><br> </p> <p> <label for="heard">Heard about us via *:</label> <select id="heard" required=""> <option value="">Choose..</option> <option value="press">Press</option> <option value="net">Internet</option> <option value="mouth">Word of mouth</option> <option value="other">Other..</option> </select> </p> <p> <label for="message">Message (20 chars min, 100 max) :</label> <textarea id="message" class="form-control" name="message" data-parsley-trigger="keyup" data-parsley-minlength="20" data-parsley-maxlength="100" data-parsley-minlength-message="Come on! You need to enter at least a 20 character comment.." data-parsley-validation-threshold="10"></textarea> </p> <br> <input type="submit" class="btn btn-default" value="validate"> <p><small>* Please, note that this demo form is not a perfect example of UX-awareness. The aim here is to show a quick overview of parsley-API and Parsley customizable behavior.</small></p> </form> <script type="text/javascript"> $(function () { $('#demo-form').parsley().on('field:validated', function() { var ok = $('.parsley-error').length === 0; $('.bs-callout-info').toggleClass('hidden', !ok); $('.bs-callout-warning').toggleClass('hidden', ok); }) .on('form:submit', function() { return false; // Don't submit form for this demo }); }); </script>

Parsley Events to Make Complex Validations

<h4>Correctly fill at least one of these blocks</h4> <form class="demo-form" data-parsley-validate=""> <div class="first"> <label for="firstname">Firstname:</label> <input type="text" class="form-control" name="firstname" data-parsley-length="[4, 20]" data-parsley-group="block1"> <label for="lastname">Lastname:</label> <input type="text" class="form-control" name="lastname" data-parsley-length="[4, 20]" data-parsley-group="block1"> </div> <hr> <div class="second"> <label for="fullname">Fullname:</label> <input type="text" class="form-control" name="fullname" data-parsley-length="[8, 40]" data-parsley-group="block2"> </div> <div class="invalid-form-error-message"></div> <input type="submit" class="btn btn-default validate"> </form> <script type="text/javascript"> $(function () { $('.demo-form').parsley().on('form:validate', function (formInstance) { var ok = formInstance.isValid({group: 'block1', force: true}) || formInstance.isValid({group: 'block2', force: true}); $('.invalid-form-error-message') .html(ok ? '' : 'You must correctly fill *at least one of these two blocks!') .toggleClass('filled', !ok); if (!ok) formInstance.validationResult = false; }); }); </script>

Multi Step Validation in Parsley

<form class="demo-form"> <div class="form-section"> <label for="firstname">First Name:</label> <input type="text" class="form-control" name="firstname" required=""> <label for="lastname">Last Name:</label> <input type="text" class="form-control" name="lastname" required=""> </div> <div class="form-section"> <label for="email">Email:</label> <input type="email" class="form-control" name="email" required=""> </div> <div class="form-section"> <label for="color">Favorite color:</label> <input type="text" class="form-control" name="color" required=""> </div> <div class="form-navigation"> <button type="button" class="previous btn btn-info pull-left">< Previous</button> <button type="button" class="next btn btn-info pull-right">Next ></button> <input type="submit" class="btn btn-default pull-right"> <span class="clearfix"></span> </div> </form> <script type="text/javascript"> $(function () { var $sections = $('.form-section'); function navigateTo(index) { // Mark the current section with the class 'current' $sections .removeClass('current') .eq(index) .addClass('current'); // Show only the navigation buttons that make sense for the current section: $('.form-navigation .previous').toggle(index > 0); var atTheEnd = index >= $sections.length - 1; $('.form-navigation .next').toggle(!atTheEnd); $('.form-navigation [type=submit]').toggle(atTheEnd); } function curIndex() { // Return the current index by looking at which section has the class 'current' return $sections.index($sections.filter('.current')); } // Previous button is easy, just go back $('.form-navigation .previous').click(function() { navigateTo(curIndex() - 1); }); // Next button goes forward iff current block validates $('.form-navigation .next').click(function() { $('.demo-form').parsley().whenValidate({ group: 'block-' + curIndex() }).done(function() { navigateTo(curIndex() + 1); }); }); // Prepare sections by setting the `data-parsley-group` attribute to 'block-0', 'block-1', etc. $sections.each(function(index, section) { $(section).find(':input').attr('data-parsley-group', 'block-' + index); }); navigateTo(0); // Start at the beginning }); </script>

Make Custom Validators in Parsley

<form id="demo-form" data-parsley-validate=""> <label for="question">Please enter a palindrome:</label> <input type="text" class="form-control" name="s" required="" data-parsley-palindrome=""> <label for="question">Please enter a multiple of 3:</label> <input type="text" class="form-control" name="nb" required="" data-parsley-multiple-of="3"> <label for="question">Please provide a file smaller than 42Kb:</label> <input type="file" name="f" required="" data-parsley-max-file-size="42"> <input type="submit" class="btn btn-default pull-right"> </form> <script type="text/javascript"> window.Parsley.addValidator('palindrome', { validateString: function(value) { return value.split('').reverse().join('') === value; }, messages: { en: 'This string is not the reverse of itself', fr: "Cette valeur n'est pas l'inverse d'elle même." } }); window.Parsley.addValidator('multipleOf', { validateNumber: function(value, requirement) { return value % requirement === 0; }, requirementType: 'integer', messages: { en: 'This value should be a multiple of %s.', fr: "Ce nombre n'est pas un multiple de %s." } }); window.Parsley.addValidator('maxFileSize', { validateString: function(_value, maxSize, parsleyInstance) { if (!window.FormData) { alert('You are making all developpers in the world cringe. Upgrade your browser!'); return true; } var files = parsleyInstance.$element[0].files; return files.length != 1 || files[0].size <= maxSize * 1024; }, requirementType: 'integer', messages: { en: 'This file should not be larger than %s Kb', fr: 'Ce fichier est plus grand que %s Kb.' } }); </script>

Promises and AJAX Form Validation

<h1>Custom validators</h1> <h3>Simple ajax request</h3> <form data-parsley-validate=""> <label for="zip">US Zip Code * :</label> <input name="zip" required="" data-parsley-type="digits" data-parsley-length="[5,5]" data-parsley-zip="us"> <br> <input type="submit" value="validate"> <p><small>* This checks the actual existence of a zip code using ajax (e.g.: 00001 is not an actual US Zip code).</small></p> </form> <h3>Complex ajax handling</h3> <form class="complex"> <fieldset data-parsley-state-and-zip="us" data-parsley-validate-if-empty="" data-parsley-errors-container=".error"> <h4>Location</h4><span class="error"></span> <label for="state">US State:</label> <select name="state" required=""> <option value="" disabled="" selected="" hidden="">Select a US State...</option> <option value="AL">Alabama</option><option value="AK">Alaska</option><option value="AZ">Arizona</option><option value="AR">Arkansas</option><option value="CA">California</option><option value="CO">Colorado</option><option value="CT">Connecticut</option><option value="DE">Delaware</option><option value="DC">District Of Columbia</option><option value="FL">Florida</option><option value="GA">Georgia</option><option value="HI">Hawaii</option><option value="ID">Idaho</option><option value="IL">Illinois</option><option value="IN">Indiana</option><option value="IA">Iowa</option><option value="KS">Kansas</option><option value="KY">Kentucky</option><option value="LA">Louisiana</option><option value="ME">Maine</option><option value="MD">Maryland</option><option value="MA">Massachusetts</option><option value="MI">Michigan</option><option value="MN">Minnesota</option><option value="MS">Mississippi</option><option value="MO">Missouri</option><option value="MT">Montana</option><option value="NE">Nebraska</option><option value="NV">Nevada</option><option value="NH">New Hampshire</option><option value="NJ">New Jersey</option><option value="NM">New Mexico</option><option value="NY">New York</option><option value="NC">North Carolina</option><option value="ND">North Dakota</option><option value="OH">Ohio</option><option value="OK">Oklahoma</option><option value="OR">Oregon</option><option value="PA">Pennsylvania</option><option value="RI">Rhode Island</option><option value="SC">South Carolina</option><option value="SD">South Dakota</option><option value="TN">Tennessee</option><option value="TX">Texas</option><option value="UT">Utah</option><option value="VT">Vermont</option><option value="VA">Virginia</option><option value="WA">Washington</option><option value="WV">West Virginia</option><option value="WI">Wisconsin</option><option value="WY">Wyoming</option> </select> <br> <label for="state">Zip:</label> <input name="zip" required="" data-parsley-type="digits" data-parsley-length="[5,5]" data-parsley-zip="us"> </fieldset> <br> <input type="submit" value="validate"> <p><small>* A complete example showing Ajax, promise chaining, dynamic custom error message, interdependent fields.</small></p> </form> <script type="text/javascript"> Parsley.addValidator('zip', { validateString: function(value, country) { // Zippopotam.us returns a status 404 for incorrect zip codes, // so we simply return the ajax request: return $.ajax('//www.zippopotam.us/' + country + '/' + value) }, messages: {en: 'There is no such zip for the country "%s"'} }); Parsley.addValidator('stateAndZip', { validateString: function(_ignoreValue, country, instance) { var state = instance.$element.find('[name="state"]').val(); var zip = instance.$element.find('[name="zip"]').val(); var xhr = $.ajax('//www.zippopotam.us/' + country + '/' + zip) // When Zippopotam.us returns the info of the given zip, check it: return xhr.then(function(json) { var actualState = json.places[0]['state abbreviation']; if (actualState !== state) { // We could return `false`, but for an even better result // we can fail the promise with a custom error message: return $.Deferred().reject("The zip code " + zip + " is in " + actualState + ", not in " + state); // Note: in jQuery 3.0+, you can `throw('my custom error')` for the same result } }) }, // The following error message will still show if the xhr itself fails // (404 because zip does not exist, network error, etc.) messages: {en: 'There is no such zip for the country "%s"'} }); $(function() { $('.complex').parsley({ inputs: Parsley.options.inputs + ',fieldset' }) }); Parsley.on('form:submit', function() { return false; // Don't submit form for this demo }); </script>

Stylish Error Messages Right Next to Input Fields

<div class="bt-form__wrapper"> <form class="uk-form bt-flabels js-flabels" data-parsley-validate data-parsley-errors-messages-disabled> <div class="uk-grid uk-grid-collapse"> <div class="uk-width-1-2"> <div class="bt-flabels__wrapper"> <label>First Name</label> <input type="text" name="first_name" placeholder="First Name" autocomplete="off" data-parsley-required /> <span class="bt-flabels__error-desc">Required</span> </div> </div> <div class="uk-width-1-2"> <div class="bt-flabels__wrapper bt-flabels--right"> <label>Last Name</label> <input type="text" name="last_name" autocomplete="off" placeholder="Last Name" data-parsley-required /> <span class="bt-flabels__error-desc">Required</span> </div> </div> </div> <div class="bt-flabels__wrapper"> <label>Email</label> <input type="text" name="email" placeholder="name@website.com" data-parsley-required data-parsley-type="email" autocomplete="off" /> <span class="bt-flabels__error-desc">Required/Invalid Email</span> </div> <div class="bt-flabels__wrapper"> <label>Phone (# used as password)</label> <input type="text" name="phone" data-parsley-required placeholder="Phone (# used as password)" autocomplete="off" /> <span class="bt-flabels__error-desc">Required/Invalid Phone</span> </div> <div class="uk-text-center uk-margin-top"> <button type="submit" class="uk-button uk-button-primary uk-button-large js-submit">Submit</button> </div> </form> </div>

@border-color: #c8c8c8; @active-bg: #f5f8fc; @active-color: #52a6e1; @anim: cubic-bezier(0.215, 0.610, 0.355, 1.00); @error-bg: #feeeee; @error-color: darken(@error-bg, 35); .bt-form__wrapper { margin: 30px auto; max-width: 500px; } .bt-flabels { input[type] { position: relative; width: 100%; height: 50px; border: none; border-radius: 0; z-index: 1; transition: background 0.3s @anim, border-color 0.3s @anim; &:focus { background: @active-bg; } } label { pointer-events: none; position: absolute; opacity: 0; top: 0; transform: translateY(15%); z-index: 2; font-weight: bold; font-size: 10px; text-transform: uppercase; padding-left: 6px; color: @active-color; transition: transform 0.3s @anim, opacity 0.3s @anim; } >*:not(:first-child) { &.bt-flabels__wrapper, .bt-flabels__wrapper { border-top: none; } } } .bt-flabels__wrapper { position: relative; border: 1px solid @border-color; } .bt-flabels__error-desc { position: absolute; top: 0; right: 6px; opacity: 0; font-weight: bold; color: @error-color; font-size: 10px; text-transform: uppercase; z-index: 3; pointer-events: none; } .bt-flabels__error { input[type] { background: @error-bg; &:focus { background: @error-bg; } } .bt-flabels__error-desc { opacity: 1; transform: translateY(0); } } .bt-flabels--right { border-left: none; } .bt-flabel__float { label { opacity: 1; transform: translateY(0); } input[type] { padding-top: 9px; } }