FormValidation v0.8.1 is released, supports Bootstrap 4 alpha 3

Supporting Skeleton framework

Examples

Below is a step by step instruction showing how to validate the forms which uses the Skeleton framework.

Downloading the files

  • Create a file named skeleton.js with the following content:
/**
 * This class supports validating Skeleton framework (http://getskeleton.com/)
 */
(function($) {
    FormValidation.Framework.Skeleton = function(element, options) {
        options = $.extend(true, {
            button: {
                selector: '[type="submit"]:not([formnovalidate])',
                // The class of disabled button
                disabled: 'fv-button-disabled'
            },
            err: {
                clazz: 'fv-help-block',
                parent: '^.*columns.*$'
            },
            // Skeleton doesn't support feedback icon
            icon: {
                valid: null,
                invalid: null,
                validating: null,
                feedback: 'fv-control-feedback'
            },
            row: {
                selector: '.row',
                valid: 'fv-has-success',
                invalid: 'fv-has-error',
                feedback: 'fv-has-feedback'
            }
        }, options);

        FormValidation.Base.apply(this, [element, options]);
    };

    FormValidation.Framework.Skeleton.prototype = $.extend({}, FormValidation.Base.prototype, {
        /**
         * Specific framework might need to adjust the icon position
         *
         * @param {jQuery} $field The field element
         * @param {jQuery} $icon The icon element
         */
        _fixIcon: function($field, $icon) {
            var ns      = this._namespace,
                type    = $field.attr('type'),
                field   = $field.attr('data-' + ns + '-field'),
                $row    = $field.closest(this.options.fields[field].row || this.options.row.selector),
                $parent = $field.parent();

            // Place it after the container of checkbox/radio
            // so when clicking the icon, it doesn't effect to the checkbox/radio element
            if ('checkbox' === type || 'radio' === type) {
                if ($parent.is('label')) {
                    $parent.addClass('fv-' + type);
                    $icon.insertAfter($parent);
                }
            }

            var $labels = $row.find('label');
            if ($labels.length === 0 || $labels.eq(0).is($parent)) {
                $icon.addClass('fv-icon-no-label');
            }
        }
    });
}(jQuery));
  • Create a file named skeleton.css with the following content:
.fv-form-skeleton .row {
    margin-bottom: 15px;
}

.fv-form-skeleton input,
.fv-form-skeleton select,
.fv-form-skeleton textarea {
    margin-bottom: 0;
}

.fv-form-skeleton .fv-control-feedback {
    top: 0;
    width: 38px;
    height: 38px;
    line-height: 38px;
}

.fv-form-skeleton label~.fv-control-feedback {
    top: 29px;
}

.fv-form-skeleton label>.label-body {
    padding-top: 7px;
}

/* Stacked form without label */
.fv-form-skeleton label~.fv-control-feedback.fv-icon-no-label {
    top: 0;
}

/* Horizontal form */
.fv-form-horizontal.fv-form-skeleton label.fv-checkbox~.fv-control-feedback,
.fv-form-horizontal.fv-form-skeleton label.fv-radio~.fv-control-feedback {
    top: 0;
}

.fv-form-skeleton .fv-help-block {
    margin-top: 5px;
}

/* You can customize the color of success and error classes */
.fv-form-skeleton .fv-has-error label,
.fv-form-skeleton .fv-has-error .fv-help-block,
.fv-form-skeleton .fv-has-error .fv-control-feedback {
    color: red;
}
.fv-form-skeleton .fv-has-success label,
.fv-form-skeleton .fv-has-success .fv-control-feedback {
    color: green;
}

/* You can customize the disabled button styles */
.fv-form-skeleton .fv-button-disabled {
    cursor: not-allowed;
    opacity: .65;
}

You should place skeleton.js and skeleton.css in formvalidation/dist/js/framework and formvalidation/dist/css directories respectively.

Including the library

<!-- Skeleton framework -->
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css">

<!-- Optional: Include the Font Awesome for using some icons -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" />

<!-- FormValidation CSS file -->
<link rel="stylesheet" href="/vendor/formvalidation/dist/css/formValidation.min.css">
<link rel="stylesheet" href="/vendor/formvalidation/dist/css/skeleton.css">

<!-- jQuery v1.9.1 or higher -->
<script type="text/javascript" src="/vendor/jquery/jquery.min.js"></script>

<!-- FormValidation plugin and the class supports validating Skeleton form -->
<script src="/vendor/formvalidation/dist/js/formValidation.min.js"></script>
<script src="/vendor/formvalidation/dist/js/framework/skeleton.js"></script>

Calling the plugin

When calling .formValidation(), you need to set the framework option:

$(form).formValidation({
    framework: 'skeleton',
    ...
});
Some of forms use the row option to support multiple fields in the same row container

Stacked form

<form id="signupForm" method="post">
    <div class="row">
        <div class="six columns">
            <label>First name</label>
            <input name="firstName" type="text" class="u-full-width" />
        </div>

        <div class="six columns">
            <label>Last name</label>
            <input name="lastName" type="text" class="u-full-width" />
        </div>
    </div>

    <div class="row">
        <div class="four columns">
            <label>Username</label>
            <input name="username" type="text" class="u-full-width" />
        </div>

        <div class="four columns">
            <label>Email address</label>
            <input name="email" type="text" class="u-full-width" />
        </div>

        <div class="four columns">
            <label>Password</label>
            <input name="password" type="password" class="u-full-width" />
        </div>
    </div>

    <div class="row">
        <label>Gender</label>
        <label>
            <input name="gender" type="radio" value="male" />
            <span class="label-body">Male</span>
        </label>
        <label>
            <input name="gender" type="radio" value="female" />
            <span class="label-body">Female</span>
        </label>
        <label>
            <input name="gender" type="radio" value="other" />
            <span class="label-body">Other</span>
        </label>
    </div>

    <div class="row">
        <label>
            <span id="captchaOperation"></span>
            <span class="label-body">
                <input type="text" name="captcha" class="u-full-width" />
            </span>
        </label>
    </div>

    <div class="row">
        <label>
            <input name="agree" type="checkbox" />
            <span class="label-body">Agree with the terms and conditions</span>
        </label>
    </div>

    <div class="row">
        <button type="submit" class="button-primary">Sign up</button>
    </div>
</form>

<script>
$(document).ready(function() {
    // Generate a simple captcha
    function randomNumber(min, max) {
        return Math.floor(Math.random() * (max - min + 1) + min);
    };
    $('#captchaOperation').html([randomNumber(1, 100), '+', randomNumber(1, 200), '='].join(' '));

    $('#signupForm').formValidation({
        framework: 'skeleton',
        icon: {
            valid: 'fa fa-check',
            invalid: 'fa fa-times',
            validating: 'fa fa-refresh',
            feedback: 'fv-control-feedback'
        },
        fields: {
            firstName: {
                row: '.six',
                validators: {
                    notEmpty: {
                        message: 'The first name is required'
                    }
                }
            },
            lastName: {
                row: '.six',
                validators: {
                    notEmpty: {
                        message: 'The last name is required'
                    }
                }
            },
            username: {
                row: '.four',
                validators: {
                    notEmpty: {
                        message: 'The username is required'
                    },
                    stringLength: {
                        min: 6,
                        max: 30,
                        message: 'The username must be more than 6 and less than 30 characters long'
                    },
                    regexp: {
                        regexp: /^[a-zA-Z0-9_\.]+$/,
                        message: 'The username can only consist of alphabetical, number, dot and underscore'
                    }
                }
            },
            email: {
                row: '.four',
                validators: {
                    notEmpty: {
                        message: 'The email address is required'
                    },
                    emailAddress: {
                        message: 'The input is not a valid email address'
                    }
                }
            },
            password: {
                row: '.four',
                validators: {
                    notEmpty: {
                        message: 'The password is required'
                    },
                    different: {
                        field: 'username',
                        message: 'The password cannot be the same as username'
                    }
                }
            },
            gender: {
                validators: {
                    notEmpty: {
                        message: 'The gender is required'
                    }
                }
            },
            captcha: {
                validators: {
                    callback: {
                        message: 'Wrong answer',
                        callback: function(value, validator) {
                            var items = $('#captchaOperation').html().split(' '), sum = parseInt(items[0]) + parseInt(items[2]);
                            return value == sum;
                        }
                    }
                }
            },
            agree: {
                validators: {
                    notEmpty: {
                        message: 'You must agree with the terms and conditions'
                    }
                }
            }
        }
    });
});
</script>

Stacked form without labels

<form id="signinForm" method="post">
    <div class="row">
        <input name="username" type="text" class="u-full-width" placeholder="Username" />
    </div>

    <div class="row">
        <input name="password" type="password" class="u-full-width" placeholder="Username" />
    </div>

    <div class="row">
        <button type="submit" class="button-primary">Sign in</button>
    </div>
</form>

<script>
$(document).ready(function() {
    $('#signinForm').formValidation({
        framework: 'skeleton',
        icon: {
            valid: 'fa fa-check',
            invalid: 'fa fa-times',
            validating: 'fa fa-refresh',
            feedback: 'fv-control-feedback'
        },
        fields: {
            username: {
                validators: {
                    notEmpty: {
                        message: 'The username is required'
                    },
                    stringLength: {
                        min: 6,
                        max: 30,
                        message: 'The username must be more than 6 and less than 30 characters long'
                    },
                    regexp: {
                        regexp: /^[a-zA-Z0-9_]+$/,
                        message: 'The username can only consist of alphabetical, number and underscore'
                    }
                }
            },
            password: {
                validators: {
                    notEmpty: {
                        message: 'The password is required'
                    }
                }
            }
        }
    });
});
</script>

Horizontal form

<form id="signupForm" class="fv-form-horizontal" method="post">
    <div class="row">
        <label class="three columns">Full name</label>

        <div class="four columns">
            <input name="firstName" type="text" class="u-full-width" placeholder="First name" />
        </div>

        <div class="four columns">
            <input name="lastName" type="text" class="u-full-width" placeholder="Last name" />
        </div>
    </div>

    <div class="row">
        <label class="three columns">Username</label>

        <div class="six columns">
            <input name="username" type="text" class="u-full-width" />
        </div>
    </div>

    <div class="row">
        <label class="three columns">Email address</label>

        <div class="six columns">
            <input name="email" type="text" class="u-full-width" />
        </div>
    </div>

    <div class="row">
        <label class="three columns">Password</label>

        <div class="six columns">
            <input name="password" type="password" class="u-full-width" />
        </div>
    </div>

    <div class="row">
        <label class="three columns">Gender</label>

        <div class="six columns">
            <label>
                <input name="gender" type="radio" value="male" />
                <span class="label-body">Male</span>
            </label>
            <label>
                <input name="gender" type="radio" value="female" />
                <span class="label-body">Female</span>
            </label>
            <label>
                <input name="gender" type="radio" value="other" />
                <span class="label-body">Other</span>
            </label>
        </div>
    </div>

    <div class="row">
        <label class="three columns">
            <span id="captchaOperation"></span>
        </label>

        <div class="two columns">
            <input type="text" name="captcha" class="u-full-width" />
        </div>
    </div>

    <div class="row">
        <label class="three columns"></label>
        <div class="eight columns">
            <label>
                <input name="agree" type="checkbox" />
                <span class="label-body">Agree with the terms and conditions</span>
            </label>
        </div>
    </div>

    <div class="row">
        <label class="three columns"></label>
        <div class="nine columns">
            <button type="submit" class="button-primary">Sign up</button>
        </div>
    </div>
</form>

<script>
$(document).ready(function() {
    // Generate a simple captcha
    function randomNumber(min, max) {
        return Math.floor(Math.random() * (max - min + 1) + min);
    };
    $('#captchaOperation').html([randomNumber(1, 100), '+', randomNumber(1, 200), '='].join(' '));

    $('#signupForm').formValidation({
        framework: 'skeleton',
        row: {
            selector: '.columns'
        },
        icon: {
            valid: 'fa fa-check',
            invalid: 'fa fa-times',
            validating: 'fa fa-refresh',
            feedback: 'fv-control-feedback'
        },
        fields: {
            firstName: {
                validators: {
                    notEmpty: {
                        message: 'The first name is required'
                    }
                }
            },
            lastName: {
                validators: {
                    notEmpty: {
                        message: 'The last name is required'
                    }
                }
            },
            username: {
                validators: {
                    notEmpty: {
                        message: 'The username is required'
                    },
                    stringLength: {
                        min: 6,
                        max: 30,
                        message: 'The username must be more than 6 and less than 30 characters long'
                    },
                    regexp: {
                        regexp: /^[a-zA-Z0-9_\.]+$/,
                        message: 'The username can only consist of alphabetical, number, dot and underscore'
                    }
                }
            },
            email: {
                validators: {
                    notEmpty: {
                        message: 'The email address is required'
                    },
                    emailAddress: {
                        message: 'The input is not a valid email address'
                    }
                }
            },
            password: {
                validators: {
                    notEmpty: {
                        message: 'The password is required'
                    },
                    different: {
                        field: 'username',
                        message: 'The password cannot be the same as username'
                    }
                }
            },
            gender: {
                validators: {
                    notEmpty: {
                        message: 'The gender is required'
                    }
                }
            },
            captcha: {
                validators: {
                    callback: {
                        message: 'Wrong answer',
                        callback: function(value, validator) {
                            var items = $('#captchaOperation').html().split(' '), sum = parseInt(items[0]) + parseInt(items[2]);
                            return value == sum;
                        }
                    }
                }
            },
            agree: {
                validators: {
                    notEmpty: {
                        message: 'You must agree with the terms and conditions'
                    }
                }
            }
        }
    });
});
</script>