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

Showing messages in a modal

Examples

By default, FormValidation will place error messages right below the field. In this example, I will show you a way of placing the messages in a Bootstrap modal. All messages are then shown up when user click the submit button.

Although the live forms in this example use the Bootstrap modal component, the same approach can be used with other modal, dialog libraries as long as they provide methods to show and hide the modal. Below are some of popular one:

Using the container option

Assume that you want to place all messages inside a div element which belongs to body of a Bootstrap modal as following:

<form id="signupForm" method="post" class="form-horizontal">
    ...
</form>

<!-- Modal for displaying the messages -->
<div class="modal fade" id="messageModal">
    <div class="modal-dialog">
        <div class="modal-content">
            ...

            <div class="modal-body">
                <!-- The messages container -->
                <div id="errors"></div>
            </div>

            ...
        </div>
    </div>
</div>

In order to archive that, we can set the err.container option to CSS selector which indicates the messages container:

$('#signupForm').formValidation({
    err: {
        container: '#errors'
    },
    ...
});

Finally, trigger the err.form.fv event which is called when the form is not valid to display the modal:

$('#signupForm').on('err.form.fv', function(e) {
    // Show the message modal
    $('#messageModal').modal('show');
});

It's too easy, isn't it?

In the following form, you can fill in some fields and click the Sign up button to see how it works:

<form id="signupForm" method="post" class="form-horizontal">
    <div class="form-group">
        <label class="col-xs-3 control-label">Full name</label>
        <div class="col-xs-4">
            <input type="text" class="form-control" name="firstName" placeholder="First name" />
        </div>
        <div class="col-xs-4">
            <input type="text" class="form-control" name="lastName" placeholder="Last name" />
        </div>
    </div>

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

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

    <div class="form-group">
        <label class="col-xs-3 control-label">Password</label>
        <div class="col-xs-5">
            <input type="password" class="form-control" name="password" />
        </div>
    </div>

    <div class="form-group">
        <label class="col-xs-3 control-label">Gender</label>
        <div class="col-xs-5">
            <div class="radio">
                <label>
                    <input type="radio" name="gender" value="male" /> Male
                </label>
            </div>
            <div class="radio">
                <label>
                    <input type="radio" name="gender" value="female" /> Female
                </label>
            </div>
            <div class="radio">
                <label>
                    <input type="radio" name="gender" value="other" /> Other
                </label>
            </div>
        </div>
    </div>

    <div class="form-group">
        <label class="col-xs-3 control-label">Bio</label>
        <div class="col-xs-8">
            <textarea class="form-control" name="bio" rows="5" style="width: 100%"></textarea>
        </div>
    </div>

    <div class="form-group">
        <div class="col-xs-9 col-xs-offset-3">
            <button type="submit" class="btn btn-primary" name="signup" value="Sign up">Sign up</button>
        </div>
    </div>
</form>

<!-- Modal for displaying the messages -->
<div class="modal fade" id="messageModal" tabindex="-1" role="dialog" aria-labelledby="Login" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
                <h5 class="modal-title">Errors</h5>
            </div>

            <div class="modal-body">
                <!-- The messages container -->
                <div id="errors"></div>
            </div>

            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
            </div>
        </div>
    </div>
</div>

<script>
$(document).ready(function() {
    $('#signupForm')
        .formValidation({
            framework: 'bootstrap',
            err: {
                container: '#errors'
            },
            icon: {
                valid: 'glyphicon glyphicon-ok',
                invalid: 'glyphicon glyphicon-remove',
                validating: 'glyphicon glyphicon-refresh'
            },
            fields: {
                firstName: {
                    row: '.col-xs-4',
                    validators: {
                        notEmpty: {
                            message: 'The first name is required'
                        }
                    }
                },
                lastName: {
                    row: '.col-xs-4',
                    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 5 and less than 31 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 email address is not valid'
                        }
                    }
                },
                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'
                        }
                    }
                },
                bio: {
                    validators: {
                        stringLength: {
                            max: 300,
                            message: 'The bio must be less than 300 characters long'
                        }
                    }
                }
            }
        })
        .on('err.form.fv', function(e) {
            // Show the message modal
            $('#messageModal').modal('show');
        });
});
</script>

Bonus: Focusing on the field when clicking the message

In the example above, all the messages are simply placed inside a modal. There's no connections between each particular message with associated field. It will give better experiences if the invalid field is focused when we click on any of its message.

This can be done by triggering some events as described in details in the Showing messages in custom area example.

In the piece of code below, there's only one additional thing which is that we need to hide the modal before focusing on the field:

$('#signupForm')
    .formValidation(...)
    .on('err.field.fv', function(e, data) {
        ...

        // Loop over the messages
        for (var i in messages) {
            // Create new 'li' element to show the message
            $('<li/>')
                .attr('data-field', data.field)
                .wrapInner(
                    $('<a/>')
                        .attr('href', 'javascript: void(0);')
                        .html(messages[i])
                        .on('click', function(e) {
                            // Hide the modal first
                            $('#messageModal').modal('hide');

                            // Focus on the invalid field
                            data.element.focus();
                        })
                )
                .appendTo('#errors');
        }

        ...
    });
Again, it's recommended to look at this section to understand how the events are used to archive what we want
<form id="signupForm" method="post" class="form-horizontal">
    <div class="form-group">
        <label class="col-xs-3 control-label">Full name</label>
        <div class="col-xs-4">
            <input type="text" class="form-control" name="firstName" placeholder="First name" />
        </div>
        <div class="col-xs-4">
            <input type="text" class="form-control" name="lastName" placeholder="Last name" />
        </div>
    </div>

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

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

    <div class="form-group">
        <label class="col-xs-3 control-label">Password</label>
        <div class="col-xs-5">
            <input type="password" class="form-control" name="password" />
        </div>
    </div>

    <div class="form-group">
        <label class="col-xs-3 control-label">Gender</label>
        <div class="col-xs-5">
            <div class="radio">
                <label>
                    <input type="radio" name="gender" value="male" /> Male
                </label>
            </div>
            <div class="radio">
                <label>
                    <input type="radio" name="gender" value="female" /> Female
                </label>
            </div>
            <div class="radio">
                <label>
                    <input type="radio" name="gender" value="other" /> Other
                </label>
            </div>
        </div>
    </div>

    <div class="form-group">
        <label class="col-xs-3 control-label">Bio</label>
        <div class="col-xs-8">
            <textarea class="form-control" name="bio" rows="5" style="width: 100%"></textarea>
        </div>
    </div>

    <div class="form-group">
        <div class="col-xs-9 col-xs-offset-3">
            <button type="submit" class="btn btn-primary" name="signup" value="Sign up">Sign up</button>
        </div>
    </div>
</form>

<!-- Modal for displaying the messages -->
<div class="modal fade" id="messageModal" tabindex="-1" role="dialog" aria-labelledby="Login" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
                <h5 class="modal-title">Errors</h5>
            </div>

            <div class="modal-body">
                <!-- The messages container -->
                <ul id="errors"></ul>
            </div>

            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
            </div>
        </div>
    </div>
</div>

<script>
$(document).ready(function() {
    $('#signupForm')
        .formValidation({
            framework: 'bootstrap',
            err: {
                container: '#errors'
            },
            icon: {
                valid: 'glyphicon glyphicon-ok',
                invalid: 'glyphicon glyphicon-remove',
                validating: 'glyphicon glyphicon-refresh'
            },
            fields: {
                firstName: {
                    row: '.col-xs-4',
                    validators: {
                        notEmpty: {
                            message: 'The first name is required'
                        }
                    }
                },
                lastName: {
                    row: '.col-xs-4',
                    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 5 and less than 31 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 email address is not valid'
                        }
                    }
                },
                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'
                        }
                    }
                },
                bio: {
                    validators: {
                        stringLength: {
                            max: 300,
                            message: 'The bio must be less than 300 characters long'
                        }
                    }
                }
            }
        })
        .on('success.form.fv', function(e) {
            // Reset the message element when the form is valid
            $('#errors').html('');
        })
        .on('err.field.fv', function(e, data) {
            // data.fv      --> The FormValidation instance
            // data.field   --> The field name
            // data.element --> The field element

            // Get the messages of field
            var messages = data.fv.getMessages(data.element);

            // Remove the field messages if they're already available
            $('#errors').find('li[data-field="' + data.field + '"]').remove();

            // Loop over the messages
            for (var i in messages) {
                // Create new 'li' element to show the message
                $('<li/>')
                    .attr('data-field', data.field)
                    .wrapInner(
                        $('<a/>')
                            .attr('href', 'javascript: void(0);')
                            .html(messages[i])
                            .on('click', function(e) {
                                // Hide the modal first
                                $('#messageModal').modal('hide');

                                // Focus on the invalid field
                                data.element.focus();
                            })
                    )
                    .appendTo('#errors');
            }

            // Hide the default message
            // data.element.data('fv.messages') returns the field messages element
            data.element
                .data('fv.messages')
                .find('.help-block[data-fv-for="' + data.field + '"]')
                .hide();
        })
        .on('success.field.fv', function(e, data) {
            // Remove the field messages
            $('#errors').find('li[data-field="' + data.field + '"]').remove();
        })
        .on('err.form.fv', function(e) {
            // Show the message modal
            $('#messageModal').modal('show');
        });
});
</script>

Bonus: Keep showing errors below field and inside the modal

If you want to show the error messages in both right below the field as usual and inside the modal, we don't need to use the err.container option.

Instead, we find all the available error messages and push it to the modal:

$('#signupForm')
    .formValidation({
        // Don't use the `err.container` option
        // so the error messages are shown below the field as usual
    })
    .on('err.form.fv', function(e) {
        // Reset the errors inside the modal first
        $('#errors').html('');

        $('#signupForm')
            // Find all the error messages
            .find('[data-fv-validator][data-fv-result="INVALID"]')
            // And update the error inside the modal body
            .clone().appendTo('#errors');

        // Show the message modal
        $('#messageModal').modal('show');
    });
<form id="signupForm" method="post" class="form-horizontal">
    <div class="form-group">
        <label class="col-xs-3 control-label">Full name</label>
        <div class="col-xs-4">
            <input type="text" class="form-control" name="firstName" placeholder="First name" />
        </div>
        <div class="col-xs-4">
            <input type="text" class="form-control" name="lastName" placeholder="Last name" />
        </div>
    </div>

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

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

    <div class="form-group">
        <label class="col-xs-3 control-label">Password</label>
        <div class="col-xs-5">
            <input type="password" class="form-control" name="password" />
        </div>
    </div>

    <div class="form-group">
        <label class="col-xs-3 control-label">Gender</label>
        <div class="col-xs-5">
            <div class="radio">
                <label>
                    <input type="radio" name="gender" value="male" /> Male
                </label>
            </div>
            <div class="radio">
                <label>
                    <input type="radio" name="gender" value="female" /> Female
                </label>
            </div>
            <div class="radio">
                <label>
                    <input type="radio" name="gender" value="other" /> Other
                </label>
            </div>
        </div>
    </div>

    <div class="form-group">
        <label class="col-xs-3 control-label">Bio</label>
        <div class="col-xs-8">
            <textarea class="form-control" name="bio" rows="5" style="width: 100%"></textarea>
        </div>
    </div>

    <div class="form-group">
        <div class="col-xs-9 col-xs-offset-3">
            <button type="submit" class="btn btn-primary" name="signup" value="Sign up">Sign up</button>
        </div>
    </div>
</form>

<!-- Modal for displaying the messages -->
<div class="modal fade" id="messageModal" tabindex="-1" role="dialog" aria-labelledby="Login" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
                <h5 class="modal-title">Errors</h5>
            </div>

            <div class="modal-body">
                <!-- The messages container -->
                <div id="errors"></div>
            </div>

            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
            </div>
        </div>
    </div>
</div>

<script>
$(document).ready(function() {
    $('#signupForm')
        .formValidation({
            framework: 'bootstrap',
            icon: {
                valid: 'glyphicon glyphicon-ok',
                invalid: 'glyphicon glyphicon-remove',
                validating: 'glyphicon glyphicon-refresh'
            },
            fields: {
                firstName: {
                    row: '.col-xs-4',
                    validators: {
                        notEmpty: {
                            message: 'The first name is required'
                        }
                    }
                },
                lastName: {
                    row: '.col-xs-4',
                    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 5 and less than 31 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 email address is not valid'
                        }
                    }
                },
                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'
                        }
                    }
                },
                bio: {
                    validators: {
                        stringLength: {
                            max: 300,
                            message: 'The bio must be less than 300 characters long'
                        }
                    }
                }
            }
        })
        .on('err.form.fv', function(e) {
            // Reset the errors inside the modal first
            $('#errors').html('');

            $('#signupForm')
                // Find all the error messages
                .find('[data-fv-validator][data-fv-result="INVALID"]')
                // And update the error inside the modal body
                .clone().appendTo('#errors');

            // Show the message modal
            $('#messageModal').modal('show');
        });
});
</script>

Related examples