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

Showing messages in custom area

Examples

There are many developers asking me for an example that demonstrates the ability of showing messages in custom area.

Here are few of scenarios which you might want to use this feature:

  • Messages are shown above or below the form due to the limitation of form height
  • Messages are shown in a help panel located at the right of form
  • Messages are shown in the last step of a wizard
  • etc

There are two ways to solve this requirement which are listed in the next sections.

Using the container option

The first solution which is easiest way is to use the container option.

This option indicates where the error messages are shown.

Value Description
CSS selector All error messages are placed in element defined by this CSS selector
A callback

A callback returns the element that the messages are placed in:

function($field, validator) {
    // $field is the field element
    // validator is the plugin instance
};
tooltip Error messages of each field are placed inside a tooltip
popover Error messages of each field are placed inside a popover

The contact form below shows messages in an element located at the bottom of form.

<form id="contactForm" method="post" class="form-horizontal">
    <div class="form-group">
        <label class="col-xs-3 control-label">Full name</label>
        <div class="col-xs-6">
            <input type="text" class="form-control" name="fullName" />
        </div>
    </div>

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

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

    <div class="form-group">
        <label class="col-xs-3 control-label">Content</label>
        <div class="col-xs-6">
            <textarea class="form-control" name="content" rows="5"></textarea>
        </div>
    </div>

    <!-- #messages is where the messages are placed inside -->
    <div class="form-group">
        <div class="col-xs-9 col-xs-offset-3">
            <div id="messages"></div>
        </div>
    </div>

    <div class="form-group">
        <div class="col-xs-9 col-xs-offset-3">
            <button type="submit" class="btn btn-default">Validate</button>
        </div>
    </div>
</form>

<script>
$(document).ready(function() {
    $('#contactForm').formValidation({
        framework: 'bootstrap',
        err: {
            container: '#messages'
        },
        icon: {
            valid: 'glyphicon glyphicon-ok',
            invalid: 'glyphicon glyphicon-remove',
            validating: 'glyphicon glyphicon-refresh'
        },
        fields: {
            fullName: {
                validators: {
                    notEmpty: {
                        message: 'The full name is required and cannot be empty'
                    }
                }
            },
            email: {
                validators: {
                    notEmpty: {
                        message: 'The email address is required and cannot be empty'
                    },
                    emailAddress: {
                        message: 'The email address is not valid'
                    }
                }
            },
            title: {
                validators: {
                    notEmpty: {
                        message: 'The title is required and cannot be empty'
                    },
                    stringLength: {
                        max: 100,
                        message: 'The title must be less than 100 characters long'
                    }
                }
            },
            content: {
                validators: {
                    notEmpty: {
                        message: 'The content is required and cannot be empty'
                    },
                    stringLength: {
                        max: 500,
                        message: 'The content must be less than 500 characters long'
                    }
                }
            }
        }
    });
});
</script>

If you want to place messages which their positions depend on the field, you can use a callback. The following form places messages in the right:

<form id="contactForm" 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="fullName" />
        </div>
        <div class="col-xs-5 messageContainer"></div>
    </div>

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

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

    <div class="form-group">
        <label class="col-xs-3 control-label">Content</label>
        <div class="col-xs-4">
            <textarea class="form-control" name="content" rows="5"></textarea>
        </div>
        <div class="col-xs-5 messageContainer"></div>
    </div>

    <div class="form-group">
        <div class="col-xs-9 col-xs-offset-3">
            <button type="submit" class="btn btn-default">Validate</button>
        </div>
    </div>
</form>

<script>
$(document).ready(function() {
    $('#contactForm').formValidation({
        framework: 'bootstrap',
        err: {
            container: function($field, validator) {
                // Look at the markup
                //  <div class="col-xs-4">
                //      <field>
                //  </div>
                //  <div class="col-xs-5 messageContainer"></div>
                return $field.parent().next('.messageContainer');
            }
        },
        icon: {
            valid: 'glyphicon glyphicon-ok',
            invalid: 'glyphicon glyphicon-remove',
            validating: 'glyphicon glyphicon-refresh'
        },
        fields: {
            fullName: {
                validators: {
                    notEmpty: {
                        message: 'The full name is required and cannot be empty'
                    }
                }
            },
            email: {
                validators: {
                    notEmpty: {
                        message: 'The email address is required and cannot be empty'
                    },
                    emailAddress: {
                        message: 'The email address is not valid'
                    }
                }
            },
            title: {
                validators: {
                    notEmpty: {
                        message: 'The title is required and cannot be empty'
                    },
                    stringLength: {
                        max: 100,
                        message: 'The title must be less than 100 characters long'
                    }
                }
            },
            content: {
                validators: {
                    notEmpty: {
                        message: 'The content is required and cannot be empty'
                    },
                    stringLength: {
                        max: 500,
                        message: 'The content must be less than 500 characters long'
                    }
                }
            }
        }
    });
});
</script>

Using the events

Using the container option works fine. The messages are placed inside span elements with .help-block class. You might will ask for more customizations such as:

  • I want to place each message inside a li element, therefore I can customize the style later
  • I want to hide the default messages as well
  • When click the message, I want the associated field to be focused

It's possible to solve these requirements by using the methods and events below:

Event/Method Description
success.form.fv event Triggered when the form is valid
err.field.fv event Triggered when any field is invalid
success.field.fv event Triggered when any field is valid
getMessages(field) method Get the field messages

Looking at the HTML and JS tabs to see how we get the job done.

<style type="text/css">
/* Simple message styles customization */
#errors {
    border-left: 5px solid #a94442;
    padding-left: 15px;
}
#errors li {
    list-style-type: none;
}
#errors li:before {
    content: '\b7\a0';
}
</style>

<form id="sendMessageForm" method="post" class="form-horizontal">
    <div class="form-group">
        <label class="col-xs-3 control-label">Full name</label>
        <div class="col-xs-6">
            <input type="text" class="form-control" name="fullName" />
        </div>
    </div>

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

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

    <div class="form-group">
        <label class="col-xs-3 control-label">Content</label>
        <div class="col-xs-6">
            <textarea class="form-control" name="content" rows="5"></textarea>
        </div>
    </div>

    <!-- Show the messages in #errors -->
    <div class="form-group">
        <div class="col-xs-9 col-xs-offset-3">
            <ul id="errors"></ul>
        </div>
    </div>

    <div class="form-group">
        <div class="col-xs-9 col-xs-offset-3">
            <button type="submit" class="btn btn-default">Validate</button>
        </div>
    </div>
</form>

<script>
$(document).ready(function() {
    $('#sendMessageForm')
        .formValidation({
            framework: 'bootstrap',
            icon: {
                valid: 'glyphicon glyphicon-ok',
                invalid: 'glyphicon glyphicon-remove',
                validating: 'glyphicon glyphicon-refresh'
            },
            fields: {
                fullName: {
                    validators: {
                        notEmpty: {
                            message: 'The full name is required and cannot be empty'
                        }
                    }
                },
                email: {
                    validators: {
                        notEmpty: {
                            message: 'The email address is required and cannot be empty'
                        },
                        emailAddress: {
                            message: 'The email address is not valid'
                        }
                    }
                },
                title: {
                    validators: {
                        notEmpty: {
                            message: 'The title is required and cannot be empty'
                        },
                        stringLength: {
                            max: 100,
                            message: 'The title must be less than 100 characters long'
                        }
                    }
                },
                content: {
                    validators: {
                        notEmpty: {
                            message: 'The content is required and cannot be empty'
                        },
                        stringLength: {
                            max: 500,
                            message: 'The content must be less than 500 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) {
                                // 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();
        });
});
</script>

Related examples