<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<div class="container">
<div class="row">
<h2>Webenlance's javascript form validation for bootstrap</h2>
<p>Please Hit like if you love this</p>
<a href="webenlance.com" target="blank">Webenlance</a>
</div>
</div>
<form class="form-horizontal simple-validation" id="frmExample" novalidate>
<div class="form-group required">
<label for="name" class="col-sm-2 control-label">Name</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="name" placeholder="Enter your name" data-title="Please enter your name">
</div>
</div>
<div class="form-group required">
<label for="emailaddress" class="col-sm-2 control-label">Email</label>
<div class="col-sm-10">
<input type="email" class="form-control" id="emailaddress" placeholder="Enter email" data-title="Please enter a valid Email">
</div>
</div>
<div class="form-group required">
<label for="age" class="col-sm-2 control-label">Age</label>
<div class="col-sm-10">
<input type="number" class="form-control" id="age" placeholder="Enter your age" data-title="Age required - Only numeric values allowed">
</div>
</div>
<div class="form-group required">
<label for="income" class="col-sm-2 control-label">Income</label>
<div class="col-sm-10">
<input type="text" class="form-control float" id="income" placeholder="Enter your income" data-title="Income field required - Only numeric or decimal values allowed">
</div>
</div>
<div class="form-group required">
<label for="password" class="col-sm-2 control-label">Password</label>
<div class="col-sm-10">
<input type="password" class="form-control regex" id="password" placeholder="Enter password" data-title="Password required" data-regex="^[^\s]{6,20}$" data-regex-title="Please a enter a password 6 - 20 characters in length">
</div>
</div>
<div class="form-group required">
<label for="passwordConfirm" class="col-sm-2 control-label">Confirm</label>
<div class="col-sm-10">
<input type="password" class="form-control match" id="passwordConfirm" placeholder="Enter password confirmation" data-title="Confirmation password required" data-match="password" data-match-title="Your password and confirmation password do not match">
</div>
</div>
<div class="form-group">
<label for="terms" class="col-sm-2 control-label required">Terms</label>
<div class="col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox" name="checkme" id="terms" class="required" data-title="You must agree to the terms"> Check Me
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="frmPrc hide">
<button type="button" class="btn btn-primary" disabled="disabled"><i class="fa fa-spinner fa-spin"></i> Processing</button>
</div>
<div class="frmBtn">
<button type="submit" class="btn btn-primary"><i class="fa fa-save"></i> Submit</button>
<button type="submit" class="btn btn-danger delete"><i class="fa fa-trash"></i> Delete</button>
</div>
</div>
</div>
</form>
.required label,
label.required{
font-weight:bold;
}
.required label:before,
label.required:before{
color:#c00;
content:"* ";
}
var Validate = {
'date': function(value){
return !(/Invalid|NaN/).test(new Date(value));
},
'dateTime': function(value){
return !(/Invalid|NaN/).test(new Date(value));
},
'email': function(value){
return (/^[_a-zA-Z0-9\-]+((\.[_a-zA-Z0-9\-]+)*|(\+[_a-zA-Z0-9\-]+)*)*@[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)*(\.[a-zA-Z]{2,4})$/i).test(value);
},
'float': function(value){
return (/^[\-+]?[0-9]*\.?[0-9]+$/).test(value);
},
'integer': function (value){
return (/^\d+$/).test(value);
},
'slug': function(value){
// at least 3 alpha numerics no spaces and no periods
return (/[\w]{3,}[\-]?$/).test(value) && !(/\s/).test(value) && !(/\./).test(value);
}
};
// !FormButtons
/**
* @hint Global FormButtons object which defines the class or id used by the submit and processing button holders
*/
var FormButtons = {
"process" : "frmPrc",
"submit" : "frmBtn"
};
/**
* @hint Pass in a form and bind the submit event to the validation process (validateForm)
*/
function simpleValidation(form,doAlert){
if (form === undefined)
return false;
if (doAlert === undefined)
doAlert = false;
// continue
window.jQuery(form).submit(function () {
var o = {
message : '',
err : [],
checks : []
};
// handle the form buttons show and hide functionality
formButtons(true,this);
// loop thru each input
o = validateForm(this);
// run extra validation if exists
try{
var e = window[window.jQuery(this).data('extend-validation')];
if(typeof(e) === 'function'){
o = e(window.jQuery(this),o);
}
}
catch(a){/* ignore error */}
// notification or submit
if (o.err.length) {
o.form = this;
// focus and select on required field
if (doAlert){
window.alert('Attention:' + o.message.replace(/<li>/gm,'\n').replace(/<\/li>/gm,''));
formButtons(false,this);
} else {
openDialog(o);
}
return false;
} else {
// submit form
return true;
}
});
}
/**
* @hint The validation process bound by simpleValidation or calling directly, requires passing a form
*/
function validateForm(form){
var o = {
message : '',
err : [],
checks : [],
form : form
};
window.jQuery(form).find('.required input,.required select,.required textarea,input.required, select.required, textarea.required').each(function () {
// get the type and name
var me = window.jQuery(this),
type = me.attr('type'),
name = me.attr('name'),
label = me.parents('.control-group, .form-group').find('label');
// skip me if I am disabled
if (this.disabled)
return;
// handle tinymce
if (me.hasClass('mceEditor') && window.tinyMCE !== undefined )
window.tinyMCE.get(this.id).save(); // auto save any mceEditor value back to textarea
if (
((type === 'checkbox' || type === 'radio') && !window.jQuery('input[name='+name+']').is(':checked') && o.checks.indexOf(name) < 0) ||
((type === 'email' || me.hasClass('email')) && !Validate.email(me.val())) ||
((type === 'number' || me.hasClass('integer')) && !Validate.integer(me.val())) ||
(me.hasClass('float') && !Validate.float(me.val())) ||
((me.hasClass('timepicker') || me.hasClass('time')) && !Validate.dateTime(me.val())) ||
((me.hasClass('datepicker') || me.hasClass('date') || me.hasClass('datetime')) && !Validate.date(me.val())) ||
(me.hasClass('slug') && !Validate.slug(me.val())) ||
me.val() === '' ||
(me.hasClass('match') && me.data('match') && me.val() !== window.jQuery('#' + me.data('match')).val()) ||
(me.hasClass('regex') && me.data('regex') && !this.value.match(new RegExp(me.data('regex'))))
){
if (me.val() !== '' && me.data('regex-title') && !this.value.match(new RegExp(me.data('regex')))){
o.message += '<li>' + me.data('regex-title') + '</li>';
}else if (me.val() !== '' && me.hasClass('match') && me.data('match-title')){
o.message += '<li>' + me.data('match-title') + '</li>';
}else if (me.data('title')){
o.message += '<li>' + me.data('title') + '</li>';
}else if (me.attr('title')){
o.message += '<li>' + me.attr('title') + '</li>';
}else{
o.message += '<li>' + (label.length === 0 ? name : label.text()) + ' is a required field</li>';
}
o.err.push(me);
// push to the checks array so we only evaluate once
o.checks.push(name);
}
});
return o;
}
/**
* @hint Checks if a dialog div exists and if not it creates it
*/
function createDialog(o){
// create if not exists
if(document.getElementById('dialog') === null){
window.jQuery('body').append('<div id="dialog"></div>');
}
// we might have been called while one is open if so close me
else if (document.getElementById('dialog').style.display !== 'none'){
window.jQuery('body')
.find('#dialog, .modal-backdrop').remove().end()
.append('<div id="dialog"></div>');
}
// get it so we can add it and remove all classes to make sure we start fresh
var dl = window.jQuery('#dialog').removeClass().addClass('modal');
// handle if fade on
if (o.dofade === true)
dl.addClass('fade');
// handle if extra class
if (o.dialogclass !== '')
dl.addClass(o.dialogclass);
}
/**
* @hint Create dialog header
*/
function createDialogHeader(o){
var headingTag = (getBootstrapVersion() >= 3 ? "h4" : "h3");
return (o.noheader === false ? '<div class="modal-header"><a href="#" class="close" data-dismiss="modal">×</a><'+ headingTag + ' class="modal-title">' + (o.header || 'Attention') + '</'+ headingTag + '></div>' : '');
}
/**
* @hint Create dialog body
*/
function createDialogBody(o){
var bodyClass = (o.noerror === false ? 'text-error' :''),
bodyStyle = "",
asList = o.message.indexOf('<li>') !== -1 && o.message.indexOf('<ul>') === -1,
tag = asList === true ? 'ul' : 'div',
height = 0;
if (o.noheader === false)
height += 70;
if (o.nofooter === false)
height += 70;
// check for width/ height settings
if (getBootstrapVersion() >= 3){
// bs 3 the height and width is on the modal-body
if (o.width !== 0)
bodyStyle += 'width:' + o.width + 'px;';
if (o.height !== 0)
bodyStyle += 'height:' + (o.height - height) + 'px;';
}
else{
if (o.maxheight === true)
bodyStyle = "max-height:100% !important;";
if (o.height !== 0)
bodyStyle += 'height:' + (o.height - height) + 'px;';
}
if (bodyStyle !== '')
bodyStyle = 'style="' + bodyStyle + '"';
return '<div class="modal-body"' + bodyStyle + '>' +
'<'+ tag + ' class="' + bodyClass +'">' +
o.message +
'</' + tag + '>' +
'</div>';
}
/**
* @hint Create dialog footer
*/
function createDialogFooter(o,withActions){
var str = '',
fa = getFontAwesomePrefix();
if (o.nofooter !== true){
str = '<div class="modal-footer">';
// custom footer
if (o.customfooter !== ''){
str += o.customfooter;
}
else if (withActions === true)
{
str += '<div class="hide"><button class="btn btn-info" disabled="disabled"><i class="'+ fa.required + fa.prefix + 'refresh ' + fa.prefix + 'spin"></i> Processing Request</button></div><div class="show">';
// include confirm button
if (o.includeconfirmbtn === true) {
str +='<a href="#" class="btn btn-confirm ' + o.confirmButtonColorClass + '">' + o.confirmButtonText + '</a>';
}
// cancel button
str += '<a href="#" class="btn ' + o.cancelButtonColorClass + '" data-dismiss="modal">' + o.cancelButtonText + '</a></div>';
}
else
{
str += '<a href="#" class="btn ' + o.confirmButtonColorClass + '" data-dismiss="modal">' + o.confirmText + '</a>';
}
str += '</div>';
}
return str;
}
/**
* @hint Set dialog defaults required
*/
function setDialogDefaults(o){
var defaults = {
background : '', // background color applied to modal-backdrop
callback : null, // function to run on Action Dialog close
cancelButtonColorClass : 'btn-danger', // Default class for Cancel Button
cancelButtonText : 'No', // Default text for Cancel Button
confirmButtonColorClass : 'btn-primary', // Default class for Confirmation Button
confirmButtonText : 'Yes', // Default text for Confirmation Button on Action Dialog
confirmText : 'OK', // Default text for Confirmation Button on Regular Dialog
customfooter : '', // Custom Footer
destroy : true, // destroys div when closed
dialogclass : '', // class that gets added to dialog div
dofade : true, // animate when open
dostatic : false, // modal - must close with click to button
err : [], // holds an array of the fields with errors
form : null, // holds the form element of the form currently being validated
header : null, // custom header string
height : 0, // height of dialog - applied differently depending on version
includeconfirmbtn : true, // include confirm button on Action Dialog
keyboard : false, // keyboard events
maxheight : false, // bs version 2 property used with height
message : '', // message to display in modal
noerror : false, // If message is error - true sets text to red
nofooter : false, // Remove footer
noheader : false, // Remove header
parent : null, // Parent of element that called, can be self or id of a parent
width : 0
};
return window.jQuery.extend( defaults, o );
}
/**
* @hint Activates the dialog - all requirements and then opens
*/
function activateDialog(o,dl){
// overwrite dimensions if passed (only bs2)
if (getBootstrapVersion() < 3){
if (o.width !== 0)
dl.css({'max-width': o.width,'width': o.width,'margin-left':-(o.width/2)});
if (o.height !== 0)
dl.css({'max-height':o.height,'height':o.height});
} else if (o.width !== 0){
if (o.width !== 0)
dl.find('.modal-dialog').css({'max-width': o.width,'width': o.width});
}
// open modal
if (o.dostatic === true)
dl.modal({backdrop:'static',show:true,keyboard:o.keyboard});
else
dl.modal({backdrop:true,show:true,keyboard:o.keyboard});
// change color
if (o.background !== '')
dl.next().css('background-color',o.background);
// fix for iphone view
dl.on(getBootstrapEvent('shown'),function(){
if (window.innerHeight <= 480)
window.jQuery(this).css({top:window.scrollY+10});
});
}
/**
* @hint Show/Hide form process
*/
function formButtons(theState,theForm){
var runGlobal = false;
// this allows us to pass in and search for items with the class name instead (multiple forms in page way)
if (theForm !== undefined) {
// auto assign id if blank
if (theForm.id === '')
theForm.id = 'un_' + (new Date().getTime());
runGlobal = window.jQuery('#' + theForm.id + ' .' + FormButtons.process).length === 0;
}
if (runGlobal === false && theForm !== undefined) {
if (theState === true)
showHide(theForm.id + ' .' + FormButtons.process, theForm.id + ' .' + FormButtons.submit);
else
showHide(theForm.id + ' .' + FormButtons.submit, theForm.id + ' .' + FormButtons.process);
} else {
if (theState === true)
showHide(FormButtons.process, FormButtons.submit);
else
showHide(FormButtons.submit, FormButtons.process);
}
}
/**
* @hint Open a dialog with actions
*/
function openActionDialog(o){
var d,dl;
// set globals
o = setDialogDefaults(o);
// create dialog
createDialog(o);
// create dialog text
d = createDialogHeader(o) + createDialogBody(o) + createDialogFooter(o,true);
// insert dialog text
dl = window.jQuery('#dialog').html(parseForBootstrap(d));
// activate the dialog
activateDialog(o,dl);
// CUSTOM PROPERTIES FOR THIS TYPE
// add destroy on close
if (o.destroy === true)
dl.on(getBootstrapEvent('hidden'),function(){window.jQuery(this).remove();});
// confirm button action
dl.find('a.btn-confirm').click(function(){
// hide/show buttons
var btnProcess = dl.find('.modal-footer div.hide'),
btnSubmit = dl.find('.modal-footer div.show');
if (getBootstrapVersion() >= 3){
btnProcess.removeClass('hide');
btnSubmit.removeClass('show').addClass('hide');
} else {
btnProcess.show();
btnSubmit.hide();
}
// is function
if (o.callback && typeof(o.callback) === 'function'){
o.callback(o.parent || dl);
// is link
}else if (o.parent !== null && typeof(o.parent) === 'object' && o.parent.href !== 'undefined'){
if(o.parent.target.indexOf('blank') >= 0 || o.parent.target.indexOf('new') >= 0){
var newWindow = window.open(o.parent.href, '_blank');
newWindow.focus();
dl.modal('hide');
}else{
window.location=o.parent.href;
}
// is form
}else if (o.parent !== null){
formButtons(true);
var frm = document[o.parent] || document.getElementById(o.parent);
if (frm !== undefined)
frm.submit();
}
return false;
});
}
/**
* @hint Open a dialog
*/
function openDialog(o){
var d,dl;
// set globals
o = setDialogDefaults(o);
// create dialog
createDialog(o);
// create dialog text
d = createDialogHeader(o) + createDialogBody(o) + createDialogFooter(o,false);
// insert dialog text
dl = window.jQuery('#dialog').html(parseForBootstrap(d));
// activate the dialog
activateDialog(o,dl);
// CUSTOM PROPERTIES FOR THIS TYPE
if (o.err.length > 0 && o.form !== null){
dl.on(getBootstrapEvent('hidden'),function(){
formButtons(false,o.form);
o.err[0].focus().select();
if (o.destroy === true)
window.jQuery(this).remove();
});
} else {
// add destroy on close
if (o.destroy === true)
dl.on(getBootstrapEvent('hidden'),function(){window.jQuery(this).remove();});
}
}
/**
* @hint Gets the Font Awesome icon prefix to use
*/
function getFontAwesomePrefix(){
var fa = {required:'',prefix:'icon-'};
if (getFontAwesomeVersion() >= 4)
fa = {required:'fa ',prefix:'fa-'};
return fa;
}
/**
* @hint Gets the event to listen for depending on Bootstrap Version
*/
function getBootstrapEvent(event){
if (getBootstrapVersion() >= 3)
event += '.bs.modal';
return event;
}
/**
* @hint Prepares a modal depending on Bootstrap Version
*/
function parseForBootstrap(d){
// check if we define a bootstrap version and it is higher than or equal to 3
if (getBootstrapVersion() >= 3)
d = '<div class="modal-dialog"><div class="modal-content">' + d.replace('text-error','text-danger') + '</div></div>';
return d;
}
/**
* @hint Show/Hide elements - pass 2 elements and there view state will be toggled
*/
function showHide(a, b){
if (getBootstrapVersion() >= 3){
window.jQuery('#' + b).addClass('hide'); window.jQuery('#' + a).removeClass('hide');
}else{
window.jQuery('#' + b).hide(); window.jQuery('#' + a).show();
}
}
/**
* @hint Return Bootstrap Version defined by global variable BootstrapVersion - defaults to 3
*/
function getBootstrapVersion(){
return (typeof(BootstrapVersion) === 'number' ? BootstrapVersion : 3);
}
/**
* @hint Return FontAwesome Version defined by global variable FontAwesomeVersion - defaults to 4
*/
function getFontAwesomeVersion(){
return (typeof(FontAwesomeVersion) === 'number' ? FontAwesomeVersion : 4);
}
// !Initialize
window.jQuery(function(){
// !Simple form validation with modal
window.jQuery('form.simple-validation').each(function(){
simpleValidation(this,false);
});
// !Simple form validation with alert
window.jQuery('form.simple-validation-alert').each(function(){
simpleValidation(this,true);
});
});