I've been trying to manipulate the bootstrap tooltip's positioning without success.
Attempt #1:
stuff.tooltip({
container: 'body',
placement: function(tip, el) {
// played with tip, but it still add style: top, left at the end...
}
});
Attempt #2:
stuff.tooltip({
container: 'body',
placement: 'top'
}).on("show.bs.tooltip", function() {
// don't have access of the tip here
});
Attempt #3:
stuff.tooltip({
container: 'body',
placement: 'top'
}).on("shown.bs.tooltip", function() {
// doing anything to the tip at this point would cause visible change
});
Any ideas?
Handling with CSS
The best case scenario is you can style tooltips exclusively with CSS that is written ahead of time. As long as you don't need to dynamically change the style of the tooltip based on information only available at runtime. The CSS will immediately apply to elements inserted into the DOM without the FOUC problem.
$(function () {
$('[data-toggle="tooltip"]').tooltip({
container: 'body',
placement: 'bottom'
});
});
.tooltip .tooltip-inner {
background-color: yellow;
color: black;
}
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/js/bootstrap.js"></script>
<button type="button" class="btn btn-default"
title="Tooltip on bottom" data-toggle="tooltip" >
Tooltip on Bottom
</button>
What specifically are you trying to do where the default placement options and CSS don't apply?
Handling on Show
You can't access the tooltip during the show event... however... you can dynamically change the template option so the resulting tooltip will have custom styles.
$(function () {
$('[data-toggle="tooltip"]').tooltip({
container: 'body',
placement: 'bottom'
}).on("show.bs.tooltip", function (e) {
var $tooltip = $(this).data('bs.tooltip')
var $template = $($tooltip.options.template)
// whatever modifications you'd like to do here while invisible
$template.find('.tooltip-inner')
.css("background", "yellow")
.css("color", "black")
// reapply template
$tooltip.options.template = $template[0].outerHTML;
});
});
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/js/bootstrap.js"></script>
<button type="button" class="btn btn-default"
title="Tooltip on bottom" data-toggle="tooltip" >
Tooltip on Bottom
</button>
Handling On Shown
You could modify the tooltip template to include a hidden class, and style that with visibility: hidden;. Then, once the tooltip has appeared in the shown event, modify it however you want and finish by removing the class.
Note: do not try to use the class name hidden or hide as these are taken by bootstrap and set display:none. If the tooltip display is set to none, then the element will be incorrectly positioned. So we have to let it occupy space, but just stay invisible until we're ready to render.
$(function () {
$('[data-toggle="tooltip"]').tooltip({
container: 'body',
placement: 'bottom',
template: '<div class="tooltip init" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
}).on("shown.bs.tooltip", function (e) {
var $tooltip = $(this).data('bs.tooltip')
// whatever modifications you'd like to do here while invisible
$tooltip.$tip.find('.tooltip-inner')
.css("background", "yellow")
.css("color", "black")
// remove invisibility cloak
$tooltip.$tip.removeClass('init');
});
});
.tooltip.init {
visibility: hidden;
}
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/js/bootstrap.js"></script>
<button type="button" class="btn btn-default"
title="Tooltip on bottom" data-toggle="tooltip" >
Tooltip on bottom
</button>
Related
I don't know much of anything about Javascript, but I have a popover() function that displays pop-up text when a button is clicked. I want just the popped up text to fade automatically, about 2 seconds after the button is clicked. They way I have this piece of code set up, it closes the actual button after 2 seconds instead of the pop-up box. I figure I need to target the data-content element somehow, but I am unsure how to. Your help would be much appreciated.
<script type="text/javascript">
$(function () {
$('[data-toggle="popover"]').popover()
})
setTimeout( function () {
$('[data-content="item added"]').hide('fade')
}, 2000)
</script>
<button type="button" class="btn btn-lg btn-danger" data-toggle="popover" data-animation="true" title="Popover title" data-content="item added">Click to toggle popover</button>
this should work.
time is in milliseconds.
remove trigger line if you want the pop-over to show with click
$('[data-toggle="popover"]').popover({
delay: { "show": 1000, "hide": 2000 },
trigger: 'hover'
})
Here is an approach that uses jQuery to create a new DOM element for your tooltip and uses .fadeOut() to remove it on click. You just need to add the .tooltip-trigger class to any element with a title attribute to get the same effect across your pages.
$('.tooltip-trigger').hover(function(){
var title = $(this).attr('title');
$(this).data('tipText', title).removeAttr('title');
$('<p class="tooltip"></p>')
.text(title)
.appendTo('body')
.fadeIn('slow');
}, function() {
$(this).attr('title', $(this).data('tipText'));
$('.tooltip').remove();
});
$('.tooltip-trigger').mousemove(function(e) {
var mouseX = e.pageX + 20; //Get X coords
var mouseY = e.pageY + 10; //Get Y coords
$('.tooltip').css({ top: mouseY, left: mouseX })
});
$('.tooltip-trigger').click(function(e) {
$('.tooltip').fadeOut( "slow" );
});
.tooltip {
display:none;
position:absolute;
background-color:#ffff94;
border: 1px solid grey;
border-radius:5px;
padding:2px;
font-size: 12px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button type="button" class="btn btn-lg btn-danger tooltip-trigger" title="Popover title">Click to toggle popover</button>
Here is a fiddle.
I'm using Bootstrap 4.0 with my Rails 5.1 website. I made a popover for user details that trigger at mouse hover, it has website link in it.
<a data-toggle="popover" title="Mini profile" data-content="<%= post.user.location %><%= post.user.website %>">
<%= post.user.fullname %>
</a>
So I need popover to stay on when I move mouse hover the popover itself, so that I can click website link in it. But currently it is disappearing as soon as I move my mouse out if the link. How can I keep it open?
<script type="text/javascript">
$(document).ready(function(){
$('[data-toggle="popover"]').popover({
placement : 'bottom',
trigger : 'hover'
});
});
</script>
Thank you!
Well I quickly created a prototype as below. You need to generate the HTML markup similar to below using Rails and include the JavaScript on your page.
$("[data-toggle=popover]").each(function(i, obj) {
$(this)
.popover({
html: true,
trigger: "manual",
content: function() {
var id = $(this).attr("id");
return $("#popover-content-" + id).html();
}
})
.on("mouseenter", function() {
var _this = this;
$(this).popover("show");
$(".popover").on("mouseleave", function() {
$(_this).popover("hide");
});
})
.on("mouseleave", function() {
var _this = this;
setTimeout(function() {
if (!$(".popover:hover").length) {
$(_this).popover("hide");
}
}, 300);
});
});
.container {padding:20px;}
.form-control {width:120px;}
.popover {max-width:400px;}
#popover-content-logout > * {
background-color:#ff0000 !important;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<div class="container">
<h3>Bootstrap Popover HTML Example</h3>
<a data-toggle="popover" title="Mini Profile" data-container="body" data-placement="right" type="button" data-html="true" href="#" id="info"><span class="glyphicon glyphicon-user" style="margin:3px 0 0 0"></span> Hover Over Me</a>
<div id="popover-content-info" class="hide">
<strong>Pranav</strong><br/>
My Website
</div>
</div>
I hope someone can provide a solution for this problem. My situation is that I've got a link that has a bootstrap popover effect, everytime you hover over it, it shows an image. But the problem is that the popover container is always offset on the first time you hover over the link. My Code:
My own code is this:
<a href="{% url 'consilium:detail' movie.slug %}" class="thumbnail title-link" {% if movie.image %} data-toggle="popover" data-placement="left" data-full="{{movie.image.url}}" {% endif %}>
<span class="flex-input">
<input class="get-title" value="{{ movie.title }}" form="movie{{ forloop.counter }}" name="title" readonly/>
</span>
</a>
body .popover {
max-width: 240px;
}
.hover-image {
width: 180px;
}
-
$(document).ready(function() {
$('[data-toggle="popover"]').popover({
container: 'body',
html: true,
placement: 'left',
trigger: 'hover',
content: function() {
var url = $(this).data('full');
return '<img class="hover-image" src="' + url + '">'
}
});
});
and here is a live example:
Fiddle
Anyone knows how to fix that?
The reason this is happening is because Bootstrap absolute positions the popover on the document as soon as it is called. Then the image is loaded changing the popover height - BUT, the popover is not repositioned.
You can set a min height for the popover so that it doesn't change height and therefore doesn't need to be repositioned. Based on your example image, change css to:
body .popover {
max-width: 240px;
min-height: 160px;
}
The problem is that the popover is rendered before the image has downloaded.
To solve this, you could use the manual option in the popover plugin to define a custom hover action to show the popover after the image has loaded like this:
$this.on('mouseenter', function(){
var image = new Image();
image.onload=function(){
$this.popover('show');//Show popover after image loads
}
image.src=url; //Preload image in memory
}).on('mouseleave', function(){
$this.popover('hide');
});
});
See here for the update fiddle
My solution is just to show/hide the tooltip on initialization. Make sure to turn off animation or else there will be a flash of content. If you need animation, you can turn it back on after .tooltip('hide')
$('.xyz').tooltip({
title: "xyz <img src='https://www.idk.com/test.png'alt='blah'/>",
html: true,
placement: 'auto',
animation: false
}).tooltip('show').tooltip('hide') //.data('bs.tooltip').options.animation=true
If I want to change the class of this bootstrap button on hover with jQuery, so that the styling of the button changes to the new custom class, that I would like to add with "addClass":
<div id="tile-sort" class="btn-group" data-toggle="buttons">
<label id="sort-hello" class="btn btn-primary btn-xs">
<input type="radio" name="sort-option" value="hello">Hello
</label>
</div>
The below code works:
$('#tile-sort').hover(
function() {
$('.btn-primary').addClass('sort-hover-nonactive');
},
function() {
$('.btn-primary').removeClass('sort-hover-nonactive');
}
);
However, if I attempt to change the class of this "active" bootstrap button on hover with jQuery:
<div id="tile-sort" class="btn-group" data-toggle="buttons">
<label id="sort-goodbye" class="btn btn-primary btn-xs active">
<input type="radio" name="sort-option" value="goodbye">Goodbye
</label>
</div>
The below code does not work:
$('#tile-sort').hover(
function() {
$('.btn-primary.active').addClass('sort-hover-active');
},
function() {
$('.btn-primary.active').removeClass('sort-hover-active');
}
);
Can someone point me in the correct direction for this class adding/removing to happen?
Looks like the issue might be coming from somewhere else, maybe you didn't set !important on your custom css?
I've tried it as follows:
.sort-hover-active {
background-color:red !important;
}
Here is a demo
EDITED:
Following the comments of #jshthornton, I edited the code to be more in line with bootstrap's native code. Here is what I did:
$('#tile-sort').hover(
function() {
$('#sort-goodbye').removeClass('btn-primary').addClass('btn-danger');
},
function() {
$('#sort-goodbye').removeClass('btn-danger').addClass('btn-primary');
}
);
This way you're basically making use of existing bootstrap code instead of applying cumbersome workarounds like !important which should preferably be avoided, if possible.
And here is a demo of that
With js:
.btn-primary.active.sort-hover-active {
background-color:red;
}
Using it like this may be overwritten time to time. If this is the case just find the selector path which has the strongest weight.
http://css-tricks.com/specifics-on-css-specificity/
Without js:
.btn-primary.active:hover {
background-color:red;
}
This is the "best" way to do it if you only need visual changes on hover. This is also the least intensive to the DOM due to less mutations. With this method you can remove your JS hover code.
This also has issues in some legacy IEs. Read more here: css: does every class support :hover state?
Try with toggleClass method and hover event, check this example:
$(document).ready(function(){
$("#my-btn").hover(function(){
$(this).toggleClass("btn-danger");
});
});
<!-- libs -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<!-- button -->
<a class='btn btn-primary' id='my-btn'>
class change on hover
</a>
If you want to change the text or reuse this logic
, you can create a plugin check this example(toggleBtn plugin):
// pluglin toogleBtn
jQuery.fn.extend({
toggleBtn: function (normalBtnOps, hoverBtnOps) {
var self = this;
self.attr('class', 'btn ' + normalBtnOps.class);
self.text(normalBtnOps.text);
this.hover(function () {
self
.attr('class', 'btn ' + hoverBtnOps.class)
.text(hoverBtnOps.text);
}, function(){
self
.attr('class', 'btn ' + normalBtnOps.class)
.text(normalBtnOps.text);
});
}
});
// test Plugin
$('#my-btn').toggleBtn(
{'class': 'btn-primary','text' : 'normal btn'},
{'class': 'btn-danger','text' : 'hover btn'}
);
$('#my-btn-2').toggleBtn(
{'class': 'btn-warning','text' : 'warning!'},
{'class': 'btn-dark','text' : 'Dark!'}
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<a id='my-btn' href='#'></a>
<a id='my-btn-2' href='#'></a>
Good Luck!.
Note:
Depending on you Bootstrap version (prior to 3.3 or not), you may need a different answer.
Pay attention to the notes.
When I activate tooltips (hover over the cell) or popovers in this code, size of table is increasing. How can I avoid this?
Here emptyRow - function to generate tr with 100
<html>
<head>
<title></title>
<script type="text/javascript" language="javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<link type="text/css" rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css">
<script type="text/javascript" language="javascript" src="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.2.1/bootstrap.min.js"></script>
<style>
#matrix td {
width: 10px;
height: 10px;
border: 1px solid gray;
padding: 0px;
}
</style>
<script>
function emptyRow() {
str = '<tr>'
for (j = 0; j < 100; j++) {
str += '<td rel="tooltip" data-original-title="text"></td>'
}
str += '</tr>'
return str
}
$(document).ready(function () {
$("#matrix tr:last").after(emptyRow())
$("[rel=tooltip]").tooltip();
});
</script>
</head>
<body style="margin-top: 40px;">
<table id="matrix">
<tr>
</tr>
</table>
</body>
</html>
thank in advice!
Note: Solution for Bootstrap 3.3+
Simple Solution
In the .tooltip() call, set the container option to body:
$(function () {
$('[data-toggle="tooltip"]').tooltip({
container : 'body'
});
});
Alternatively you can do the same by using the data-container attribute:
<p data-toggle="tooltip" data-placement="left" data-container="body" title="hi">some text</p>
Why does this work?
This solves the problem because by default, the tooltip has display: block and the element is inserted in the place it was called from. Due to the display: block, it affects the page flow in some cases, i.e pushing other elements down.
By setting the container to the body element, the tooltip is appended to the body instead of where it was called from, so it doesn't affect other elements because there is nothing to "push down".
Bootstrap Tooltips Documentation
Note: Solution for Bootstrap 3.0 ~ 3.2
You need to create an element inside a td and apply a tooltip to it, like this, because a tooltip itself is a div, and when it is placed after a td element it brakes table layout.
This problem was introduced with the latest release of Bootstrap. There are ongoing discussions about fixes on GitHub here. Hopefully the next version includes the fixed files.
Note: Solution for Bootstrap 3.3+
If you want to avoid to break the table when applying a tooltip to a <td> element, you could use the following code:
$(function () {
$("body").tooltip({
selector: '[data-toggle="tooltip"]',
container: 'body'
});
})
You html could look like this:
<td data-toggle="tooltip" title="Your tooltip data">
Table Cell Content
</td>
This even works with dynamically loaded content. For example in use with datatables
I would like to add some precision to the accepted answer, I decided to use the answer format for readibility.
Note: Solution for Bootstrap 3.0 ~ 3.2
Right now, wrapping your tooltip in a div is the solution, but it will need some modifications if you want your whole <td> to show the tooltip (because of Bootstrap CSS). A simple way to do it is to transfert <td>'s padding to wrapper :
HTML
<table class="table table-hover table-bordered table-striped">
<tr>
<td>
<div class="show-tooltip" title="Tooltip content">Cell content</div>
</td>
</tr>
</table>
JS (jQuery)
$('.show-tooltip').each(function(e) {
var p = $(this).parent();
if(p.is('td')) {
/* if your tooltip is on a <td>, transfer <td>'s padding to wrapper */
$(this).css('padding', p.css('padding'));
p.css('padding', '0 0');
}
$(this).tooltip({
toggle: 'toolip',
placement: 'bottom'
});
});
If you are using datatable for table then it will be use full
$('#TableId').DataTable({
"drawCallback": function (settings) {
debugger;
$('[data-toggle="tooltip"]').tooltip({
container: 'body'
});
}
});
You should initialize Tooltip inside datatable function fnDrawCallback
"fnDrawCallback": function (data, type, full, meta) {
$('[data-toggle="tooltip"]').tooltip({ placement: 'right', title: 'heyo', container: 'body', html: true });
},
And define your column as below
{
targets: 2,
'render': function (data, type, full, meta) {
var htmlBuilder = "<b>" + data + "</b><hr/><p>Description: <br/>" + full["longDescrioption"] + "</p>";
return "<a href='#' class='Name'>" + (data.length > 50 ? data.substr(0, 50) + '…' : data) + "</a>" +
"<sup data-toggle='tooltip' data-original-title=" + htmlBuilder + ">"+
"<i class='ic-open-in-new ic' style='font-size:12px;margintop:-3px;'></i></sup>";
}
},
If you're using bootstrap directives for AngularJS, use tooltip-append-to-body attribute.
<td ng-repeat="column in row.columns" uib-tooltip="{{ ctrl.viewModel.leanings.tooltip }}" tooltip-append-to-body="true"></td>