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

Playing with Bootstrap Tabs

Examples

The following example shows that the plugin works perfectly with Bootstrap Tabs.

If you are thinking about the form wizard, look at some wizard examples

Adding invalid icon to tab

By default, the fields in inactive tabs will not be validated because they are not visible. In order to validate them, we need to use the excluded option:

excluded: [':disabled']
You should look at the basic principles when integrating FormValidation with other plugins

Assume that you want to add an icon to tab to indicate the valid or invalid tab. A tab is called valid if all fields inside it are valid. Otherwise, if there is at least one invalid field inside tab, the tab is invalid.

Firstly, we need to prepare the icon placed at the tab title:

<ul class="nav nav-tabs">
    <li class="active"><a href="#info-tab" data-toggle="tab">Tab title <i class="fa"></i></a></li>
    <li><a href="#address-tab" data-toggle="tab">Tab title <i class="fa"></i></a></li>
</ul>

Lastly, add success/error class to icon when the field is valid/invalid by triggering the err.field.fv and success.field.fv events:

$(document).ready(function() {
    $('#accountForm')
        .formValidation({
            excluded: [':disabled'],
            ...
        })

        // Called when a field is invalid
        .on('err.field.fv', function(e, data) {
            // data.element --> The field element

            var $tabPane = data.element.parents('.tab-pane'),
                tabId    = $tabPane.attr('id');

            $('a[href="#' + tabId + '"][data-toggle="tab"]')
                .parent()
                .find('i')
                .removeClass('fa-check')
                .addClass('fa-times');
        })

        // Called when a field is valid
        .on('success.field.fv', function(e, data) {
            // data.fv      --> The FormValidation instance
            // data.element --> The field element

            var $tabPane = data.element.parents('.tab-pane'),
                tabId    = $tabPane.attr('id'),
                $icon    = $('a[href="#' + tabId + '"][data-toggle="tab"]')
                            .parent()
                            .find('i')
                            .removeClass('fa-check fa-times');

            // Check if all fields in tab are valid
            var isValidTab = data.fv.isValidContainer($tabPane);
            if (isValidTab !== null) {
                $icon.addClass(isValidTab ? 'fa-check' : 'fa-times');
            }
        });
});
<style type="text/css">
#accountForm {
    margin-top: 15px;
}
</style>

<ul class="nav nav-tabs">
    <li class="active"><a href="#info-tab" data-toggle="tab">Information <i class="fa"></i></a></li>
    <li><a href="#address-tab" data-toggle="tab">Address <i class="fa"></i></a></li>
</ul>

<form id="accountForm" method="post" class="form-horizontal">
    <div class="tab-content">
        <div class="tab-pane active" id="info-tab">
            <div class="form-group">
                <label class="col-xs-3 control-label">Full name</label>
                <div class="col-xs-5">
                    <input type="text" class="form-control" name="fullName" />
                </div>
            </div>

            <div class="form-group">
                <label class="col-xs-3 control-label">Company</label>
                <div class="col-xs-5">
                    <input type="text" class="form-control" name="company" />
                </div>
            </div>

            <div class="form-group">
                <label class="col-xs-3 control-label">Job title</label>
                <div class="col-xs-5">
                    <input type="text" class="form-control" name="jobTitle" />
                </div>
            </div>
        </div>

        <div class="tab-pane" id="address-tab">
            <div class="form-group">
                <label class="col-xs-3 control-label">Address</label>
                <div class="col-xs-5">
                    <input type="text" class="form-control" name="address" />
                </div>
            </div>

            <div class="form-group">
                <label class="col-xs-3 control-label">City</label>
                <div class="col-xs-5">
                    <input type="text" class="form-control" name="city" />
                </div>
            </div>

            <div class="form-group">
                <label class="col-xs-3 control-label">Country</label>
                <div class="col-xs-5">
                    <select class="form-control" name="country">
                        <option value="">Select a country</option>
                        <option value="FR">France</option>
                        <option value="DE">Germany</option>
                        <option value="IT">Italy</option>
                        <option value="JP">Japan</option>
                        <option value="RU">Russian</option>
                        <option value="US">United State</option>
                        <option value="GB">United Kingdom</option>
                        <option value="other">Other</option>
                    </select>
                </div>
            </div>
        </div>
    </div>

    <div class="form-group" style="margin-top: 15px;">
        <div class="col-xs-5 col-xs-offset-3">
            <button type="submit" class="btn btn-default">Validate</button>
        </div>
    </div>
</form>

<script>
$(document).ready(function() {
    $('#accountForm')
        .formValidation({
            framework: 'bootstrap',
            // Only disabled elements are excluded
            // The invisible elements belonging to inactive tabs must be validated
            excluded: [':disabled'],
            icon: {
                valid: 'glyphicon glyphicon-ok',
                invalid: 'glyphicon glyphicon-remove',
                validating: 'glyphicon glyphicon-refresh'
            },
            fields: {
                fullName: {
                    validators: {
                        notEmpty: {
                            message: 'The full name is required'
                        }
                    }
                },
                company: {
                    validators: {
                        notEmpty: {
                            message: 'The company name is required'
                        }
                    }
                },
                address: {
                    validators: {
                        notEmpty: {
                            message: 'The address is required'
                        }
                    }
                },
                city: {
                    validators: {
                        notEmpty: {
                            message: 'The city is required'
                        }
                    }
                }
            }
        })
        // Called when a field is invalid
        .on('err.field.fv', function(e, data) {
            // data.element --> The field element

            var $tabPane = data.element.parents('.tab-pane'),
                tabId    = $tabPane.attr('id');

            $('a[href="#' + tabId + '"][data-toggle="tab"]')
                .parent()
                .find('i')
                .removeClass('fa-check')
                .addClass('fa-times');
        })
        // Called when a field is valid
        .on('success.field.fv', function(e, data) {
            // data.fv      --> The FormValidation instance
            // data.element --> The field element

            var $tabPane = data.element.parents('.tab-pane'),
                tabId    = $tabPane.attr('id'),
                $icon    = $('a[href="#' + tabId + '"][data-toggle="tab"]')
                            .parent()
                            .find('i')
                            .removeClass('fa-check fa-times');

            // Check if all fields in tab are valid
            var isValidTab = data.fv.isValidContainer($tabPane);
            if (isValidTab !== null) {
                $icon.addClass(isValidTab ? 'fa-check' : 'fa-times');
            }
        });
});
</script>

Activating tab containing invalid field

The following snippet shows how to activate the tab that contains the invalid field. It uses the getInvalidFields() method to retrieve the list of invalid fields, and from there, determine the tab containing the first invalid one.

If that tab isn't active, then activate it and the associated <li> element.

$(document).ready(function() {
    $('#accountForm')
        .formValidation({
            excluded: [':disabled'],
            ...
        })
        .on('err.field.fv', function(e, data) {
            // Get the first invalid field
            var $invalidFields = data.fv.getInvalidFields().eq(0);

            // Get the tab that contains the first invalid field
            var $tabPane     = $invalidFields.parents('.tab-pane'),
                invalidTabId = $tabPane.attr('id');

            // If the tab is not active
            if (!$tabPane.hasClass('active')) {
                // Then activate it
                ...

                // Focus on the field
                $invalidFields.focus();
            }
        });
});
<style type="text/css">
#accountForm {
    margin-top: 15px;
}
</style>

<ul class="nav nav-tabs">
    <li class="active"><a href="#info-tab" data-toggle="tab">Information <i class="fa"></i></a></li>
    <li><a href="#address-tab" data-toggle="tab">Address <i class="fa"></i></a></li>
</ul>

<form id="accountForm" method="post" class="form-horizontal">
    <div class="tab-content">
        <div class="tab-pane active" id="info-tab">
            <div class="form-group">
                <label class="col-xs-3 control-label">Full name</label>
                <div class="col-xs-5">
                    <input type="text" class="form-control" name="fullName" />
                </div>
            </div>

            <div class="form-group">
                <label class="col-xs-3 control-label">Company</label>
                <div class="col-xs-5">
                    <input type="text" class="form-control" name="company" />
                </div>
            </div>

            <div class="form-group">
                <label class="col-xs-3 control-label">Job title</label>
                <div class="col-xs-5">
                    <input type="text" class="form-control" name="jobTitle" />
                </div>
            </div>
        </div>

        <div class="tab-pane" id="address-tab">
            <div class="form-group">
                <label class="col-xs-3 control-label">Address</label>
                <div class="col-xs-5">
                    <input type="text" class="form-control" name="address" />
                </div>
            </div>

            <div class="form-group">
                <label class="col-xs-3 control-label">City</label>
                <div class="col-xs-5">
                    <input type="text" class="form-control" name="city" />
                </div>
            </div>

            <div class="form-group">
                <label class="col-xs-3 control-label">Country</label>
                <div class="col-xs-5">
                    <select class="form-control" name="country">
                        <option value="">Select a country</option>
                        <option value="FR">France</option>
                        <option value="DE">Germany</option>
                        <option value="IT">Italy</option>
                        <option value="JP">Japan</option>
                        <option value="RU">Russian</option>
                        <option value="US">United State</option>
                        <option value="GB">United Kingdom</option>
                        <option value="other">Other</option>
                    </select>
                </div>
            </div>
        </div>
    </div>

    <div class="form-group" style="margin-top: 15px;">
        <div class="col-xs-5 col-xs-offset-3">
            <button type="submit" class="btn btn-default">Validate</button>
        </div>
    </div>
</form>

<script>
$(document).ready(function() {
    $('#accountForm')
        .formValidation({
            framework: 'bootstrap',
            // Only disabled elements are excluded
            // The invisible elements belonging to inactive tabs must be validated
            excluded: [':disabled'],
            icon: {
                valid: 'glyphicon glyphicon-ok',
                invalid: 'glyphicon glyphicon-remove',
                validating: 'glyphicon glyphicon-refresh'
            },
            fields: {
                fullName: {
                    validators: {
                        notEmpty: {
                            message: 'The full name is required'
                        }
                    }
                },
                company: {
                    validators: {
                        notEmpty: {
                            message: 'The company name is required'
                        }
                    }
                },
                address: {
                    validators: {
                        notEmpty: {
                            message: 'The address is required'
                        }
                    }
                },
                city: {
                    validators: {
                        notEmpty: {
                            message: 'The city is required'
                        }
                    }
                }
            }
        })
        .on('err.field.fv', function(e, data) {
            // data.fv --> The FormValidation instance

            // Get the first invalid field
            var $invalidFields = data.fv.getInvalidFields().eq(0);

            // Get the tab that contains the first invalid field
            var $tabPane     = $invalidFields.parents('.tab-pane'),
                invalidTabId = $tabPane.attr('id');

            // If the tab is not active
            if (!$tabPane.hasClass('active')) {
                // Then activate it
                $tabPane.parents('.tab-content')
                        .find('.tab-pane')
                        .each(function(index, tab) {
                            var tabId = $(tab).attr('id'),
                                $li   = $('a[href="#' + tabId + '"][data-toggle="tab"]').parent();

                            if (tabId === invalidTabId) {
                                // activate the tab pane
                                $(tab).addClass('active');
                                // and the associated <li> element
                                $li.addClass('active');
                            } else {
                                $(tab).removeClass('active');
                                $li.removeClass('active');
                            }
                        });

                // Focus on the field
                $invalidFields.focus();
            }
        });
});
</script>