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:
|
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>