IMG-LOGO

Custom Form validation with Vue.js

andy - 10 Mar, 2018 12080 Views 0 Comment

In this tutorial, you will learn how to create a custom form validation in Vue.js. I will create a simple validation using the help of JQuery library for the event attachment and DOM query. If you do not want to use JQuery, feel free to change it to native Javascript. The reason why I use JQuery library is to save time in the development phase. Let's get started with the concept.

Our concept is to create the validations scripts that will cover the following validation check.

  • Check if a field is empty.
  • Check if a field contains whole numbers only.
  • Check if a field contains numbers only (float numbers).
  • Check if a field contains a valid date.
  • Check if a field contains a valid email address.
  • Check if a field contains a valid url address.
  • Check if a field contains a valid ip address.
  • Check if a field has a minimum characters entered.
  • Check if a field contains a valid alphanumeric characters.
  • Check if a field contains a valid alphanumeric characters, dash and underscore symbols.
  • Check if a field contains a valid alpha characters.
  • Check if a field contains a valid username characters. A username must contains at least one upper case English letter, one lower case English letter, one digit number, one special character and minimum 7 characters in length.

The next step is we need to create a template where we need to reduce any hardcode as minimal as possible. In order to make it works, you need to follow the following rules.

  • You are required to wrap a form inside a wrapper div that requires the following data attributes of HTML tags.
    • 1. id

      This represents the id of the validation form we want to check.

    • 2. class

      This represents the css class. You have to include a class name form-validator as this static name will be searched by our JQuery validator.

    • 3. data-validator-message

      This attribute data needs to match with the html message tag that will display a list of validation errors.

    • 4. data-button

      This attribute data needs to match with a button that will perform a form submission.

    • 5. input validator identifier

      In order for the validator to find what inputs need to be validated you will need to include a CSS class name validator. There will be three extra data attributes you will need to add. You need to include a data-name which will be the validator input name. The second one is to set data-attribute for required field. You have to include data-required='1' or data-required='yes' or data-required='true' to make an input as a required field. The last attribute is to validate for a specific type. You need to include a data-attribute='[type]'. The [type] need to be replaced with the following option: email, ip, url, alphanumericdashunderscore, alphanumeric, alpha, date, and password. If you are not required any specific type and only need a required field, you can omit this option.

    For example, let says we want to create a validation check for a registration form. The sample validation format will be like below. Note: this is only a basic standard validation without any Vue.js involved.

    			<div id="register-form" class="form-validator" data-validator-message="register-message" data-button="btnRegister">
    				<div class="form-group">
    					<label>Name</label>
    					<input type="text" class="validator" data-name="Name" data-required="1" />
    				</div>
    				<div class="form-group">
    					<label>Email Address</label>
    					<input type="text" class="validator" data-name="Email" data-required="1" data-type="email"/>
    				</div>
    				<div class="form-group">
    					<label>Password</label>
    					<input type="password" class="validator" data-name="Password" data-required="1" data-type="password"/>
    				</div>
    				<div class="form-group">
    					<button type="button" id="btnRegister" class="btn btn-primary"></button>
    				</div>
    				<div id="register-message"></div>
    			</div>
    		

The next part is to create the an example validation form with Vue.js. The only thing you need to amend is the condition for showing the error messages in Vue.js. We are going to use v-if condition to show the error messages if there is at least one invalid validation found. We then use the Vue.js for loop which is v-for to list the errors.

Here is the form code:

<div id="testing-form" class="form-validator" data-validator-message="validator-message" data-button="btnTestValidator">
	<div class="row">
		<div class="col col-md-6">
			<div class="form-group">
				<label>Name (* required)</label>
				<input type="text" class="form-control validator" data-name="Name" data-required="1"/>
			</div>
			<div class="form-group">
				<label>Email (* required)</label>
				<input type="text" class="form-control validator" data-name="Email" data-type="email" data-required="1"/>
			</div>
			<div class="form-group">
				<label>IP Address</label>
				<input type="text" class="form-control validator" data-name="IP Address" data-type="ip"/>
			</div>
			<div class="form-group">
				<label>URL Address</label>
				<input type="text" class="form-control validator" data-name="URL Address" data-type="url" style="width:60%"/>
			</div>
			<div class="form-group">
				<label>Alpha Numeric Dash Underscore</label>
				<input type="text" class="form-control validator" data-name="AlphaNumericDashUnderscore" data-type="alphanumericdashunderscore"/>
			</div>
		</div>
		<div class="col col-md-6">
			<div class="form-group">
				<label>Alpha Numeric</label>
				<input type="text" class="form-control validator" data-name="AlphaNumeric" data-type="alphanumeric"/>
			</div>
			<div class="form-group">
				<label>Alpha</label>
				<input type="text" class="form-control validator" data-name="Alpha" data-type="alpha"/>
			</div>
			<div>
				<label>Password</label>
				<input type="text" class="form-control validator" data-name="Password" data-type="password"/>
			</div>
			<div>
				<label>Date</label>
				<input type="text" class="form-control validator" data-name="Date" data-type="date"/>
			</div>
		</div>
	</div>
	<p><input type="button" id="btnTestValidator" value="Test Validator" class="btn btn-primary"  v-on:click="testValidator"/></p>
	
	<div id="validator-message" class="error-message" v-if="validationErrors.length">
		<b>Please correct the following error(s):</b>
		<ul class="ul-error">
			<li v-for="error in validationErrors">{{ error }}</li>
		</ul>
	</div>
</div>

We need some style for our validation and form. I have included the following css style.

#testing-form {
	margin:20px;
	border:solid 1px #ccc;
	padding:20px;
	border-sizing:border-box;
}

.invalid{
	border:solid 2px #ca2020 !important;
}

.error-message{
	background:#992323;
	padding:5px 15px;
	border:solid 1px #000;
	margin:10px 0;
	color:#fff;
	border-radius:5px;
}

ul.ul-error, ul.ul-error li{
	margin:0;
	padding:0;
	list-style:none;
}

ul.ul-error li{
	margin-bottom:5px;
}

After we have done the form and css style. The next thing we need to do is to include the JQuery library and Vue.js library. Here are the links:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

And here is the full javascript code of our custom validator and Vue.js instance app.

<script>
	bytutorialValidator = {
		//function to check valid integer number (whole number).
		validInteger: function (str) {
			var re = /^\d+$/;
			return re.test(str);
		},

		//function to check valid number.
		validNumber: function (str) {
			var intRegex = /^\d+$/;
			var floatRegex = /^((\d+(\.\d *)?)|((\d*\.)?\d+))$/;
			if (floatRegex.test(str) || intRegex.test(str)) {
				return true;
			}
			return false;
		},

		//function to check valid ip address.
		validIP: function (ipAddress) {
			var re = new RegExp(/\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/);
			return re.test(ipAddress);
		},

		//function to check valid url address.
		validURL: function (url) {
			var re = /^(ftp|http|https):\/\/(([a-zA-Z0-9$\-_.+!*'(),;:&=]|%[0-9a-fA-F]{2})+@)?(((25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9]|[1-9][0-9]|[0-9])(\.(25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9]|[1-9][0-9]|[0-9])){3})|localhost|([a-zA-Z0-9\-\u00C0-\u017F]+\.)+([a-zA-Z]{2,}))(:[0-9]+)?(\/(([a-zA-Z0-9$\-_.+!*'(),;:@&=]|%[0-9a-fA-F]{2})*(\/([a-zA-Z0-9$\-_.+!*'(),;:@&=]|%[0-9a-fA-F]{2})*)*)?(\?([a-zA-Z0-9$\-_.+!*'(),;:@&=\/?]|%[0-9a-fA-F]{2})*)?(\#([a-zA-Z0-9$\-_.+!*'(),;:@&=\/?]|%[0-9a-fA-F]{2})*)?)?$/;
			if (re.test(url)) {
				return true;
			} else {
				return false;
			}
		},

		//function to check valid email.
		validEmail: function (email) {
			var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
			return re.test(email);
		},

		//function to check valid date.
		validDate: function (value) {
			return!!(function(d){return(d!=='Invalid Date'&&!isNaN(d))})(new Date(value));
		},
		
		//function to check valid Alpha Numeric Dash and Underscore characters. Only a to z and A to Z and 0 to 9 and _ and - is allowed.
		validAlphaNumericDashUnderscore: function(value){
			var re = /^[a-zA-Z0-9-_]+$/;
			return re.test(value);
		},
		
		//function to check valid Alpha Numeric characters. Only a to z and A to Z and 0 to 9 is allowed.
		validAlphaNumeric: function(value){
			var re = /^[a-zA-Z0-9]+$/;
			return re.test(value);
		},
		
		//function to check valid Alpha characters. Only a to z and A to Z is allowed.
		validAlpha: function(value){
			var re = /^[a-zA-Z]+$/;
			return re.test(value);
		},
		
		//function to check valid password. Must contain at least one English letter, one digit number, one special character and minimum 7 characters in length.
		validPassword: function(value){
			var re = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{7,}/;
			return re.test(value);
		},
		
		//function to validate fields
		//** validatorMessages will hold the error validator message-box
		//** formPrefix will be identified as a validator wrapper
		validateFields: function(validatorMessages, formPrefix){
			//Just add a class validator in the input CSS class
			
			$(formPrefix + " .validator").each(function () {
				
				//add an attribute data-type='required' for a required input
				//this will perform a required field
				$(this).removeClass("invalid");
				if ($(this).val() == "" && $(this).attr("data-required") != null && ($(this).attr("data-required") == "true" || $(this).attr("data-required") == "1" || $(this).attr("data-required") == "yes")) {
					validatorMessages.push("* " + $(this).attr("data-name") + " field is required.");
					$(this).addClass("invalid");
				}
				
				//this will perform different data type
				//add the data type attribute for each informIDual check
				if($(this).attr("data-type") != null && $(this).val().length > 0){
					switch($(this).attr("data-type").toLowerCase()){
						case "integer":
							if(!bytutorialValidator.validInteger($(this).val())){
								validatorMessages.push("* " + $(this).attr("data-name") + " field can only contain whole number only.");
								$(this).addClass("invalid");
							}
							break;
						case "number":
							if(!bytutorialValidator.validNumber($(this).val())){
								validatorMessages.push("* " + $(this).attr("data-name") + " field can only contain numbers only.");
								$(this).addClass("invalid");
							}
							break;
						case "ip":
							if(!bytutorialValidator.validIP($(this).val())){
								validatorMessages.push("* " + $(this).attr("data-name") + " field contains an invalid ip address.");
								$(this).addClass("invalid");
							}
							break;
						case "url":
							if(!bytutorialValidator.validURL($(this).val())){
								validatorMessages.push("* " + $(this).attr("data-name") + " field contains an invalid url address.");
								$(this).addClass("invalid");
							}
							break;
						case "email":
							if(!bytutorialValidator.validEmail($(this).val())){
								validatorMessages.push("* " + $(this).attr("data-name") + " field contains an invalid email address.");
								$(this).addClass("invalid");
							}
							break;
						case "date":
							if(!bytutorialValidator.validDate($(this).val())){
								validatorMessages.push("* " + $(this).attr("data-name") + " field contains an invalid date.");
								$(this).addClass("invalid");
							}
							break;
						case "alphanumericdashunderscore":
							if(!bytutorialValidator.validAlphaNumericDashUnderscore($(this).val())){
								validatorMessages.push("* " + $(this).attr("data-name") + " field can only contain alpha numeric characters, dash and underscore symbols only.");
								$(this).addClass("invalid");
							}
							break;	
						case "alphanumeric":
							if(!bytutorialValidator.validAlphaNumeric($(this).val())){
								validatorMessages.push("* " + $(this).attr("data-name") + " field can only contain alpha numeric characters only.");
								$(this).addClass("invalid");
							}
							break;
						case "alpha":
							if(!bytutorialValidator.validAlpha($(this).val())){
								validatorMessages.push("* " + $(this).attr("data-name") + " field can only contain alpha characters only.");
								$(this).addClass("invalid");
							}
							break;
						case "password":
							if(!bytutorialValidator.validPassword($(this).val())){
								validatorMessages.push("* " + $(this).attr("data-name") + " field must contain at least one upper case English letter, one lower case English letter, one digit number, one special character and minimum 7 characters in length.");
								$(this).addClass("invalid");
							}
							break;
									
					}
				}
			});
			
		},
		
		//this is the main initiator, it will accept the vueapp instance. The event will be triggered on focusout. 
		initiateValidator: function (vueApp) {
			$(".validator").off("focusout");
			$(".validator").on("focusout", function (event) {
				var messageDiv = $(".form-validator").attr("data-validator-message");
				var formID = $(".form-validator").attr("id");
				if (messageDiv != null && $("#" + messageDiv).length > 0) {
					if ($("#" + messageDiv).html().length > 0) {
						var messages = new Array();
						bytutorialValidator.validateFields(messages, "#" + formID);
						if (typeof vueApp != "undefined") {
							vueApp.validationErrors = messages;
						}
					}
				}
			});
			
			//we catch the hit enter event when user in the validator input area.
			$(".validator").off("keydown");
			$(".validator").on("keydown", function (event) {
				var keycode = (event.keyCode ? event.keyCode : (event.which ? event.which : event.charCode));
				if (keycode == 13) {
					var triggerButton = $(".form-validator").attr("data-button");
					if (triggerButton != null && $("#" + triggerButton).length > 0) {
						$("#" + triggerButton).click();
					}
					return false;
				}
			});
		}
	}
	
	// create a vue instance
	var validatorForm = new Vue({
		el: '#testing-form',
		data: {
			validationErrors: [],
			formModel: []
		},
		methods: {
			testValidator: function (e) {
				this.validationErrors = [];
				bytutorialValidator.validateFields(this.validationErrors, "#testing-form");
				if (this.validationErrors.length == 0) {
					alert("All good, you are allowed to proceed ahead!!!");
				}
				e.preventDefault();
			}
		}
	});

	//we want to auto initiate the validator if we found the .form-validator css class.
	$(function(){
		if ($(".form-validator").length > 0) { bytutorialValidator.initiateValidator(validatorForm); }
	});
</script>

If we see the above code, the way the validator works is when the page has completed ready, it will then check if there is any CSS class tagged with value .form-validator. If the script found this CSS class, it will then perform a call function named initiateValidator. This function will accept an instance of Vue.js. In above example, I named the Vue.js instance as validatorForm. This validatorForm instance will have two variables data which are validationErrors which will hold a list of validation errors and the formModel is basically used to store the model or data of the inputs. The model is usually used if you want to perform a JSON post to a server.

The Vue.js instance itself, will have a method called testValidator. Inside this method, we need to initially clear the validationErrors and then we will call a function named validateFields. This function will accept two parameters which are an array object named validationErrors to hold the list of error messages. And the second parameter will be the form ID of the validator form. This function will return an errors array to a validationErrors variable. The validateFields function will work by looping all the inputs that are tagged with CSS class validator and will perform a check by looking into the attributes of the required fields and types. If it finds any error, it will add the error message into the validationErrors array. If it does not find any error list, it will then alert the user that it is good to proceed the form.

If you have any question feel free to ask a question below. I have included the demo in here.

Custom form validations with Vue.js

Please correct the following error(s):
  • {{ error }}

Download Files

You can download the above example in html format below.

Download

Comments

There are no comments available.

Write Comment
0 characters entered. Maximum characters allowed are 1000 characters.

Related Articles