Multi Step Form Wizard jQuery Validation

    In this article, we will see multi step form wizard jquery validation. Here, we will learn jquery validation for multi step form wizard. Sometimes we required multi step form to register user details, personal details, job details, etc. But we required validation for specific form fields. So, we will validate multi step form using validate js.

    So, let's see the jquery multi step form wizard with validation, multi step form validation javascript, multi step form using jquery, validate multi step form using jquery, and jquery validation plugin.

    Add HTML:

<section class="multi-step-form">

	<h4>Multi Step Form Wizard jQuery Validation - Websolutionstuff</h4>

	<div class="steps">
		<button class="active" type="button" disabled>Step One</button> |
		<button type="button" disabled>Step Two</button> |
		<button type="button" disabled>Step Three</button>
	</div>

	<form action="#" method="post">

		<fieldset aria-label="Step One" tabindex="-1" id="step-1">
			<h2>Step One</h2>
			<p>
				<label for="first-name">First Name</label>
				<input class="form-control" type="text" name="first-name" id="first-name" required>
			</p>
			<p>
				<label for="last-name">Last Name</label>
				<input class="form-control" type="text" name="last-name" id="last-name" required>
			</p>
			<p>
				<button class="btn btn-default btn-next" type="button" aria-controls="step-2">Next</button>
			</p>
		</fieldset>

		<fieldset aria-label="Step Two" tabindex="-1" id="step-2">
			<h2>Step Two</h2>
			<p>
				<label for="email-address">Email Address</label>
				<input class="form-control" type="email" name="email-address" id="email-address" required>
			</p>
			<p>
				<label for="phone-number">Phone Number <span class="optional">(optional)</span></label>
				<input class="form-control" type="tel" name="phone-number" id="phone-number">
			</p>
			<p>
				<button class="btn btn-default btn-prev" type="button" aria-controls="step-1">Previous</button>
				<button class="btn btn-default btn-next" type="button" aria-controls="step-3">Next</button>
			</p>
		</fieldset>

		<fieldset aria-label="Step Three" tabindex="-1" id="step-3">
			<h2>Step Three</h2>
			<p>
				<label for="message"></label>
				<textarea class="form-control" rows="3" name="message" id="message" required></textarea>
			</p>
			<p>
				<button class="btn btn-success" type="submit">Submit</button>
				<button class="btn btn-default btn-edit" type="button">Edit</button>
				<button class="btn btn-danger" type="reset">Start Over</button>
			</p>
		</fieldset>

	</form>
</section>

    Add CSS:

<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css" rel="stylesheet" type="text/css">
<link href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/cosmo/bootstrap.min.css" rel="stylesheet" type="text/css">
.no-js .multi-step-form fieldset button, .multi-step-form.edit-form fieldset button, .no-js .multi-step-form h2, .multi-step-form.edit-form h2 {
	 display: none !important;
}
 .no-js .multi-step-form fieldset, .multi-step-form.edit-form fieldset {
	 display: block !important;
}
 .no-js .multi-step-form [type="submit"], .multi-step-form.edit-form [type="submit"], .no-js .multi-step-form [type="reset"], .multi-step-form.edit-form [type="reset"] {
	 display: inline-block !important;
}
 .no-js .multi-step-form .steps, .multi-step-form.edit-form .steps {
	 display: none;
}
 .multi-step-form fieldset {
	 display: none;
}
 .multi-step-form fieldset:first-of-type {
	 display: block;
}
 .multi-step-form fieldset.hidden {
	 display: none;
}
 .multi-step-form fieldset.visible {
	 display: block;
}
 .multi-step-form .steps button {
	 border: 0;
}
 .multi-step-form .steps [disabled] {
	 background: none;
}
 .multi-step-form .steps .active {
	 background: #eee;
}
 body {
	 padding: 1em;
	 max-width: 35em;
	 margin: 0 auto;
}
 .error {
	 color: red;
}
 label .optional {
	 font-weight: normal;
	 font-size: 90%;
}
h4{
	font-weight:600;
	font-size:18px;
	margin-bottom:30px;
}

    Add jQuery:

<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.15.0/jquery.validate.min.js"></script>
<script>
document.documentElement.className = document.documentElement.className.replace("no-js","js");
</script>
var app = {

	init: function(){
		this.cacheDOM();
		this.setupAria();
		this.nextButton();
		this.prevButton();
		this.validateForm();
		this.startOver();
		this.editForm();
		this.killEnterKey();
		this.handleStepClicks();
	},

	cacheDOM: function(){
		if($(".multi-step-form").size() === 0){ return; }
		this.$formParent = $(".multi-step-form");
		this.$form = this.$formParent.find("form");
		this.$formStepParents = this.$form.find("fieldset"),

		this.$nextButton = this.$form.find(".btn-next");
		this.$prevButton = this.$form.find(".btn-prev");
		this.$editButton = this.$form.find(".btn-edit");
		this.$resetButton = this.$form.find("[type='reset']");

		this.$stepsParent = $(".steps");
		this.$steps = this.$stepsParent.find("button");
	},

	htmlClasses: {
		activeClass: "active",
		hiddenClass: "hidden",
		visibleClass: "visible",
		editFormClass: "edit-form",
		animatedVisibleClass: "animated fadeIn",
		animatedHiddenClass: "animated fadeOut",
		animatingClass: "animating"
	},

	setupAria: function(){

		// set first parent to visible
		this.$formStepParents.eq(0).attr("aria-hidden",false);

		// set all other parents to hidden
		this.$formStepParents.not(":first").attr("aria-hidden",true);

		// handle aria-expanded on next/prev buttons
		app.handleAriaExpanded();

	},

	nextButton: function(){

		this.$nextButton.on("click", function(e){

			e.preventDefault();

			// grab current step and next step parent
			var $this = $(this),
					currentParent = $this.closest("fieldset"),
					nextParent = currentParent.next();

					// if the form is valid hide current step
					// trigger next step
					if(app.checkForValidForm()){
						currentParent.removeClass(app.htmlClasses.visibleClass);
						app.showNextStep(currentParent, nextParent);
					}

		});
	},

	prevButton: function(){

		this.$prevButton.on("click", function(e){

			e.preventDefault();

			// grab current step parent and previous parent
			var $this = $(this),
					currentParent = $(this).closest("fieldset"),
					prevParent = currentParent.prev();

					// hide current step and show previous step
					// no need to validate form here
					currentParent.removeClass(app.htmlClasses.visibleClass);
					app.showPrevStep(currentParent, prevParent);

		});
	},

	showNextStep: function(currentParent,nextParent){

		// hide previous parent
		currentParent
			.addClass(app.htmlClasses.hiddenClass)
			.attr("aria-hidden",true);

		// show next parent
		nextParent
			.removeClass(app.htmlClasses.hiddenClass)
			.addClass(app.htmlClasses.visibleClass)
			.attr("aria-hidden",false);

		// focus first input on next parent
		nextParent.focus();

		// activate appropriate step
		app.handleState(nextParent.index());

		// handle aria-expanded on next/prev buttons
		app.handleAriaExpanded();

	},

	showPrevStep: function(currentParent,prevParent){

		// hide previous parent
		currentParent
			.addClass(app.htmlClasses.hiddenClass)
			.attr("aria-hidden",true);

		// show next parent
		prevParent
			.removeClass(app.htmlClasses.hiddenClass)
			.addClass(app.htmlClasses.visibleClass)
			.attr("aria-hidden",false);

		// send focus to first input on next parent
		prevParent.focus();

		// activate appropriate step
		app.handleState(prevParent.index());

		// handle aria-expanded on next/prev buttons
		app.handleAriaExpanded();

	},

	handleAriaExpanded: function(){

		/*
			Loop thru each next/prev button
			Check to see if the parent it conrols is visible
			Handle aria-expanded on buttons
		*/
		$.each(this.$nextButton, function(idx,item){
			var controls = $(item).attr("aria-controls");
			if($("#"+controls).attr("aria-hidden") == "true"){
				$(item).attr("aria-expanded",false);
			}else{
				$(item).attr("aria-expanded",true);
			}
		});

		$.each(this.$prevButton, function(idx,item){
			var controls = $(item).attr("aria-controls");
			if($("#"+controls).attr("aria-hidden") == "true"){
				$(item).attr("aria-expanded",false);
			}else{
				$(item).attr("aria-expanded",true);
			}
		});

	},

	validateForm: function(){
		// jquery validate form validation
		this.$form.validate({
			ignore: ":hidden", // any children of hidden desc are ignored
			errorElement: "span", // wrap error elements in span not label
			invalidHandler: function(event, validator){ // add aria-invalid to el with error
				$.each(validator.errorList, function(idx,item){
					if(idx === 0){
						$(item.element).focus(); // send focus to first el with error
					}
					$(item.element).attr("aria-invalid",true); // add invalid aria
				})
			},
			submitHandler: function(form) {
				alert("form submitted!");
		    // form.submit();
		  }
		});
	},

	checkForValidForm: function(){
		if(this.$form.valid()){
			return true;
		}
	},

	startOver: function(){

		var $parents = this.$formStepParents,
				$firstParent = this.$formStepParents.eq(0),
				$formParent = this.$formParent,
				$stepsParent = this.$stepsParent;

				this.$resetButton.on("click", function(e){

					// hide all parents - show first
					$parents
						.removeClass(app.htmlClasses.visibleClass)
						.addClass(app.htmlClasses.hiddenClass)
						.eq(0).removeClass(app.htmlClasses.hiddenClass)
						.eq(0).addClass(app.htmlClasses.visibleClass);

						// remove edit state if present
						$formParent.removeClass(app.htmlClasses.editFormClass);

						// manage state - set to first item
						app.handleState(0);

						// reset stage for initial aria state
						app.setupAria();

						// send focus to first item
						setTimeout(function(){
							$firstParent.focus();
						},200);

				}); // click

	},

	handleState: function(step){

		this.$steps.eq(step).prevAll().removeAttr("disabled");
		this.$steps.eq(step).addClass(app.htmlClasses.activeClass);

		// restart scenario
		if(step === 0){
			this.$steps
				.removeClass(app.htmlClasses.activeClass)
				.attr("disabled","disabled");
			this.$steps.eq(0).addClass(app.htmlClasses.activeClass)
		}

	},

	editForm: function(){
		var $formParent = this.$formParent,
				$formStepParents = this.$formStepParents,
				$stepsParent = this.$stepsParent;

				this.$editButton.on("click",function(){
					$formParent.toggleClass(app.htmlClasses.editFormClass);
					$formStepParents.attr("aria-hidden",false);
					$formStepParents.eq(0).find("input").eq(0).focus();
					app.handleAriaExpanded();
				});
	},

	killEnterKey: function(){
		$(document).on("keypress", ":input:not(textarea,button)", function(event) {
			return event.keyCode != 13;
		});
	},

	handleStepClicks: function(){

		var $stepTriggers = this.$steps,
				$stepParents = this.$formStepParents;

				$stepTriggers.on("click", function(e){

					e.preventDefault();

					var btnClickedIndex = $(this).index();

						// kill active state for items after step trigger
						$stepTriggers.nextAll()
							.removeClass(app.htmlClasses.activeClass)
							.attr("disabled",true);

						// activate button clicked
						$(this)
							.addClass(app.htmlClasses.activeClass)
							.attr("disabled",false)

						// hide all step parents
						$stepParents
							.removeClass(app.htmlClasses.visibleClass)
							.addClass(app.htmlClasses.hiddenClass)
							.attr("aria-hidden",true);

						// show step that matches index of button
						$stepParents.eq(btnClickedIndex)
							.removeClass(app.htmlClasses.hiddenClass)
							.addClass(app.htmlClasses.visibleClass)
							.attr("aria-hidden",false)
							.focus();

				});

	}

};

app.init();

    Output:

    multi_step_form_wizard_jquery_validation_example

    You might also like:

Bình luận
Vui lòng đăng nhập để bình luận
Một số bài viết liên quan