Flo's jQuery validate step
by Florian Bar
HTML
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<form id="form1">
<div id="accordion-wizard" class="accordion">
<h3 v-bind:class="{ 'is-done': currentStep > 1, 'is-active': currentStep == 1 }">
Step 1
</h3>
<div id="step-1" class="collapse show in" data-parent="#accordion-wizard">
<div class="form-group">
<div class="form-check">
<input id="directors-1" class="form-check-input"
type="radio" name="directorCount" value="1" v-model="directorCount">
<label class="form-check-label" for="directors-1">1</label>
</div>
<div class="form-check">
<input id="directors-2" class="form-check-input"
type="radio" name="directorCount" value="2" v-model="directorCount">
<label class="form-check-label" for="directors-3">2</label>
</div>
<div class="form-check disabled">
<input id="directors-3" class="form-check-input"
type="radio" name="directorCount" value="3" v-model="directorCount">
<label class="form-check-label" for="directors-3">3</label>
</div>
</div>
<button type="button" class="btn btn-primary" v-on:click="goToNextStep()">Next</button>
</div>
<h3 v-bind:class="{ 'is-done': currentStep > 2, 'is-active': currentStep == 2 }">
Step 2
</h3>
<div id="step-2" class="collapse" data-parent="#accordion-wizard">
<div class="form-group">
<label>First Name</label>
<input class="form-control" name="firstName" type="text" v-model="form.info.firstName" />
...
SCSS
body {
font-family: arial;
font-size: 14px;
padding: 20px;
}
.collapse:not(.in) {
// fix bootstrap accordion bug
display: none !important;
}
.is-active {
background-color: blue;
color: #fff;
}
.is-done {
background-color: green;
color: #fff;
}
.form-control.error {
margin-bottom: 0;
}
.error {
display: block;
margin-bottom: 15px;
font-size: 12px;
color: red;
}
JavaScript
var app = new Vue({
el: "#form1",
data: {
currentStep: 1, // starts at 1
directorCount: 1,
form: {
info: { firstName: "", lastName: "", email: "", tel: "" },
company: { name: "" },
directors: [
new Director()
]
}
},
watch: {
currentStep: function (newStep, prevStep) {
$("#step-" + newStep).collapse("show");
//$("#step-" + prevStep).collapse("hide");
},
directorCount: function (newDirectorCount, prevDirectorCount) {
var diff = Math.abs(newDirectorCount - prevDirectorCount);
for (var i = 0; i < diff; i++) {
if (newDirectorCount > prevDirectorCount) {
this.form.directors.push(new Director()); // add director
addDirectorValidationRules(this.form.directors.length-1);
} else {
this.form.directors.pop(); // remove director
}
}
}
},
methods: {
goToPrevStep: function() {
this.currentStep--;
},
goToNextStep: function() {
// ajax for server side validation
var stepData = this.form[this.currentStep];
if ($("#form1").valid()) {
this.currentStep++;
}
}
}
});
function Director() {
this.firstName = "";
this.lastName = "";
}
function addDirectorValidationRules(directorIndex) {
setTimeout(function() {
$("[name='directorFirstName" + directorIndex + "']").rules("add", {
required: true,
messages: {
required: "Please specify the director's first name"
}
});
$("[name='directorLastName" + directorIndex + "']").rules("add", {
required: true,
messages: {
required: "Please specify the director's last name"
}
});
});
}
$(function() {
$("#form1").validate({
rules: {
// Step 1
directorCount: "required",
// Step 2
firstName: "required",
lastName: "required",
email: { required: true, email: true },
...