Via the err.container option, FormValidation provides the ability of using tooltip to show the
error messages.
What if you want to use custom tooltip library instead of built-in tooltip component provided
by supported frameworks such as
This example is an answer of this question. By following step by step instructions, you will
learn how to use an external tooltip library for displaying the messages.
This example uses the hint library for that
purpose.
hint is one of popular libraries for creating tooltip
with pure CSS. It's also available on
Github .
Preparing the markup
Using hint is quite simple. We just need to include its CSS file firstly, and add some
HTML attributes to the element:
< link rel = "stylesheet" href = "/path/to/hint.css" >
< span class = "hint--bottom hint--error" data-hint = "Thank you!" > hover over me.</ span >
The CSS classes hint--bottom
and hint--error
indicate the
tooltip position and kind of information. hint supports other positions and kinds via
modifiers which are listed in its official website.
The problem is that it doesn't support self closing tag such as
<img/>
, <i/>
. Therefore, it's not possible for you
to attach a tooltip to an icon such as:
< i class = "glyphicon glyphicon-remove hint--bottom hint--error"
data-hint = "The username is required" ></ i >
To fix that, we need to wrap the icon inside some span
elements:
< span class = "form-control-feedback" >
< span class = "hint--bottom hint--error" data-hint = "The username is required" >
< i class = "glyphicon glyphicon-remove" ></ i >
</ span >
</ span >
Hover the mouse over the icons to see it in action:
< link href = "https://cdnjs.cloudflare.com/ajax/libs/hint.css/2.2.1/hint.min.css" rel = "stylesheet" />
< style >
. form-control-feedback {
pointer-events : auto ;
}
</ style >
< form id = "registrationForm" class = "form-horizontal" >
< div class = "form-group" >
< label class = "col-xs-3 control-label" > Full name</ label >
< div class = "col-xs-4 has-feedback has-error" >
< input type = "text" class = "form-control" name = "firstName" placeholder = "First name" />
< span class = "form-control-feedback" >
< span class = "hint--bottom hint--error" data-hint = "The first name is required" >
< i class = "glyphicon glyphicon-remove" ></ i >
</ span >
</ span >
</ div >
< div class = "col-xs-4 has-feedback has-error" >
< input type = "text" class = "form-control" name = "lastName" placeholder = "Last name" />
< span class = "form-control-feedback" >
< span class = "hint--bottom hint--error" data-hint = "The last name is required" >
< i class = "glyphicon glyphicon-remove" ></ i >
</ span >
</ span >
</ div >
</ div >
< div class = "form-group" >
< label class = "col-xs-3 control-label" > Username</ label >
< div class = "col-xs-5 has-feedback has-error" >
< input type = "text" class = "form-control" name = "username" />
< span class = "form-control-feedback" >
< span class = "hint--bottom hint--error" data-hint = "The username is required" >
< i class = "glyphicon glyphicon-remove" ></ i >
</ span >
</ span >
</ div >
</ div >
</ form >
Because the icons (i
) are generated dynamically by the plugin, we need to
trigger the init.field.fv event to prepare the
markup properly:
$ ( '#registrationForm' )
. on ( 'init.field.fv' , function ( e , data ) {
data . element // Retrieve the field element
. data ( 'fv.icon' ) // its icon element
. wrap ( $ ( '<span/>' )) // Wrap inside a span ...
. parent ()
// ... and another parent span
. wrap ( $ ( '<span/>' ). addClass ( 'form-control-feedback' ));
})
. formValidation (...);
Showing the tooltip
In this step, we need to display the tooltip when hovering the mouse over the icon. It
can be done by adding hint CSS and attribute to the target element (i.e, our created
span
element). This should happen whenever the field is invalid:
$ ( '#registrationForm' )
. on ( 'init.field.fv' , function ( e , data ) {
...
})
. formValidation (...)
. on ( 'err.field.fv' , function ( e , data ) {
var $field = data . element ,
$icon = $field . data ( 'fv.icon' ),
$messages = $field . data ( 'fv.messages' ). find ( '.help-block[data-fv-for="' + data . field + '"]' );
// Get a random message
var message = $messages . filter ( '[data-fv-result="INVALID"]' ). eq ( 0 ). html ();
$icon . removeClass ()
. addClass ( 'glyphicon glyphicon-remove' )
. parent ()
. addClass ( 'hint--bottom hint--error' )
. attr ( 'data-hint' , message );
// Hide all error messages
$messages . hide ();
});
The err.field.fv event is triggered when the field is
invalid. For more usage ejemplos, refer to the
field
events section.
As you can see above, the icon and all error messages elements can be retrieved by
$field.data('fv.icon')
and $field.data('fv.messages')
,
respectively.
Hiding the tooltip
It's more easy to hide the tooltip when the field is valid. We just remove the associated
CSS class and attribute from the target element:
$ ( '#registrationForm' )
. on ( 'init.field.fv' , function ( e , data ) {
...
})
. formValidation (...)
. on ( 'err.field.fv' , function ( e , data ) {
...
})
. on ( 'success.field.fv' , function ( e , data ) {
data . element
. data ( 'fv.icon' )
. removeClass ()
. addClass ( 'glyphicon glyphicon-ok' )
. parent ()
. removeClass ( 'hint--bottom hint--error' )
. removeAttr ( 'data-hint' );
});
As opposite of the err.field.fv event, the
success.field.fv event is triggered when the field is valid. For more usage ejemplos,
refer to the
field events section.
Final version
Finally, you can get a full working demonstration as following:
< link href = "https://cdnjs.cloudflare.com/ajax/libs/hint.css/2.2.1/hint.min.css" rel = "stylesheet" />
< style >
. form-control-feedback {
pointer-events : auto ;
}
</ style >
< form id = "registrationForm" 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" > Date of birth</ label >
< div class = "col-xs-3" >
< input type = "text" class = "form-control" name = "birthday" placeholder = "YYYY/MM/DD" />
</ 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" > Submit</ button >
</ div >
</ div >
</ form >
< script >
$ ( document ). ready ( function () {
$ ( '#registrationForm' )
. on ( 'init.field.fv' , function ( e , data ) {
data . element
. data ( 'fv.icon' )
. wrap ( $ ( '<span/>' ))
. parent ()
. wrap ( $ ( '<span/>' ). addClass ( 'form-control-feedback' ));
})
. 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 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'
}
}
},
birthday : {
validators : {
notEmpty : {
message : 'The date of birth is required'
},
date : {
format : 'YYYY/MM/DD' ,
message : 'The date of birth is not valid'
}
}
}
}
})
. on ( 'err.field.fv' , function ( e , data ) {
var $field = data . element ,
$icon = $field . data ( 'fv.icon' ),
$messages = $field . data ( 'fv.messages' ). find ( '.help-block[data-fv-for="' + data . field + '"]' );
// Get a random message
var message = $messages . filter ( '[data-fv-result="INVALID"]' ). eq ( 0 ). html ();
$icon . removeClass ()
. addClass ( 'glyphicon glyphicon-remove' )
. parent ()
. addClass ( 'hint--bottom hint--error' )
. attr ( 'data-hint' , message );
// Hide all error messages
$messages . hide ();
})
. on ( 'success.field.fv' , function ( e , data ) {
data . element
. data ( 'fv.icon' )
. removeClass ()
. addClass ( 'glyphicon glyphicon-ok' )
. parent ()
. removeClass ( 'hint--bottom hint--error' )
. removeAttr ( 'data-hint' );
});
});
</ script >