I am using twitter boostrap's popover to create a hover card to show user info, and I am triggering popover on mouseover check jsfiddle here. I want to keep this popover alive while it being hovered.
<a href="#" id="example" class="btn btn-danger" rel="popover" >hover for popover</a>
$('#example').popover({
html : true,
trigger : 'manual',
content : function() {
return '<div class="box"></div>';
}
});
$(document).on('mouseover', '#example', function(){
$('#example').popover('show');
});
$(document).on('mouseleave', '#example', function(){
$('#example').popover('hide');
});
You can think of working of facebook hover card. I want to make it same way. How can I do this?
Small modification (From the solution provided by vikas) to suit my use case.
1. Open popover on hover event for the popover button
2. Keep popover open when hovering over the popover box
3. Close popover on mouseleave for either the popover button, or the popover box.
$('.pop').popover({
trigger: 'manual',
html: true,
animation: false
})
.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);
});
I have came after another solution to this...here is the code
$('.selector').popover({
html: true,
trigger: 'manual',
container: $(this).attr('id'),
placement: 'top',
content: function () {
$return = '<div class="hover-hovercard"></div>';
}
}).on("mouseenter", function () {
var _this = this;
$(this).popover("show");
$(this).siblings(".popover").on("mouseleave", function () {
$(_this).popover('hide');
});
}).on("mouseleave", function () {
var _this = this;
setTimeout(function () {
if (!$(".popover:hover").length) {
$(_this).popover("hide")
}
}, 100);
});
Here's my take: http://jsfiddle.net/WojtekKruszewski/Zf3m7/22/
Sometimes while moving mouse from popover trigger to actual popover content diagonally, you hover over elements below. I wanted to handle such situations – as long as you reach popover content before the timeout fires, you're safe (the popover won't disappear). It requires delay
option.
This hack basically overrides Popover leave
function, but calls the original (which starts timer to hide the popover). Then it attaches a one-off listener to mouseenter
popover content element's.
If mouse enters the popover, the timer is cleared. Then it turns it listens to mouseleave
on popover and if it's triggered, it calls the original leave function so that it could start hide timer.
var originalLeave = $.fn.popover.Constructor.prototype.leave;
$.fn.popover.Constructor.prototype.leave = function(obj){
var self = obj instanceof this.constructor ?
obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
var container, timeout;
originalLeave.call(this, obj);
if(obj.currentTarget) {
container = $(obj.currentTarget).siblings('.popover')
timeout = self.timeout;
container.one('mouseenter', function(){
//We entered the actual popover – call off the dogs
clearTimeout(timeout);
//Let's monitor popover content instead
container.one('mouseleave', function(){
$.fn.popover.Constructor.prototype.leave.call(self, self);
});
})
}
};
I used the trigger set to hover
and gave the container set to the #element
and finally adding a placement of the box
to right
.
This should be your setup:
$('#example').popover({
html: true,
trigger: 'hover',
container: '#example',
placement: 'right',
content: function () {
return '<div class="box"></div>';
}
});
and #example
css needs position:relative;
check the jsfiddle below:
https://jsfiddle.net/9qn6pw4p/1/
Edited
This fiddle has both links that work with no problems http://jsfiddle.net/davidchase03/FQE57/4/
I think an easy way would be this:
$('.popover').each(function () {
var $this = $(this);
$this.popover({
trigger: 'hover',
content: 'Content Here',
container: $this
})
});
This way the popover is created inside the target element itself. so when you move your mouse over the popover, it's still over the element. Bootstrap 3.3.2 works well with this. Older version may have some problems with animation, so you may want to disable "animation:false"
This is how I did with bootstrap popover with help of other bits around the net. Dynamically gets the title and content from die various products displayed on site. Each product or popover gets unique id. Popover will disappear when exiting the product( $this .pop) or the popover. Timeout is used where will display the popover until exit through product instead of popover.
$(".pop").each(function () {
var $pElem = $(this);
$pElem.popover(
{
html: true,
trigger: "manual",
title: getPopoverTitle($pElem.attr("id")),
content: getPopoverContent($pElem.attr("id")),
container: 'body',
animation:false
}
);
}).on("mouseenter", function () {
var _this = this;
$(this).popover("show");
console.log("mouse entered");
$(".popover").on("mouseleave", function () {
$(_this).popover('hide');
});
}).on("mouseleave", function () {
var _this = this;
setTimeout(function () {
if (!$(".popover:hover").length) {
$(_this).popover("hide");
}
}, 100);
});
function getPopoverTitle(target) {
return $("#" + target + "_content > h3.popover-title").html();
};
function getPopoverContent(target) {
return $("#" + target + "_content > div.popover-content").html();
};
Here is a solution I devised that seems to work well while also allowing you to use the normal Bootstrap implementation for turning on all popovers.
Original fiddle: https://jsfiddle.net/eXpressive/hfear592/
Ported to this question:
<a href="#" id="example" class="btn btn-danger" rel="popover" >hover for popover</a>
$('#example').popover({
html : true,
trigger : 'hover',
content : function() {
return '<div class="box"></div>';
}
}).on('hide.bs.popover', function () {
if ($(".popover:hover").length) {
return false;
}
});
$('body').on('mouseleave', '.popover', function(){
$('.popover').popover('hide');
});
Vikas answer works perfectly for me, here I also add support for the delay (show / hide).
var popover = $('#example');
var options = {
animation : true,
html: true,
trigger: 'manual',
placement: 'right',
delay: {show: 500, hide: 100}
};
popover
.popover(options)
.on("mouseenter", function () {
var t = this;
var popover = $(this);
setTimeout(function () {
if (popover.is(":hover")) {
popover.popover("show");
popover.siblings(".popover").on("mouseleave", function () {
$(t).popover('hide');
});
}
}, options.delay.show);
})
.on("mouseleave", function () {
var t = this;
var popover = $(this);
setTimeout(function () {
if (popover.siblings(".popover").length && !popover.siblings(".popover").is(":hover")) {
$(t).popover("hide")
}
}, options.delay.hide);
});
Also please pay attention I changed:
if (!$(".popover:hover").length) {
with:
if (popover.siblings(".popover").length && !popover.siblings(".popover").is(":hover")) {
so that it references exactly at that opened popover, and not any other (since now, through the delay, more than 1 could be open at the same time)
The chosen answer works but will fail if the popover is initialized with the body
as the container.
$('a').popover({ container: 'body' });
A solution based on the chosen answer is the following code that needs to be placed before using the popover.
var originalLeave = $.fn.popover.Constructor.prototype.leave;
$.fn.popover.Constructor.prototype.leave = function(obj) {
var self = obj instanceof this.constructor ? obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type);
originalLeave.call(this, obj);
if (obj.currentTarget) {
self.$tip.one('mouseenter', function() {
clearTimeout(self.timeout);
self.$tip.one('mouseleave', function() {
$.fn.popover.Constructor.prototype.leave.call(self, self);
});
})
}
};
The change is minimal using self.$tip
instead of traversing the DOM expecting the popover to be always a siblings of the element.
I agree that the best way is to use the one given by: David Chase, Cu Ly, and others that the simplest way to do this is to use the container: $(this)
property as follows:
$(selectorString).each(
var $this = $(this);
$this.popover({
html: true,
placement: "top",
container: $this,
trigger: "hover",
title: "Popover",
content: "Hey, you hovered on element"
});
);
I want to point out here that the popover in this case will inherit all properties of the current element. So, for example, if you do this for a .btn
element(bootstrap), you won't be able to select text inside the popover. Just wanted to record that since I spent quite some time banging my head on this.
Simple :)
$('[data-toggle="popover"]').popover( { "container":"body", "trigger":"focus", "html":true });
$('[data-toggle="popover"]').mouseenter(function(){
$(this).trigger('focus');
});
Same thing for tooltips:
For me following solution works because it does not add event listeners on every 'mouseenter' and it is possible to hover back on the tooltip element which keeps the tooltip alive.
$ ->
$('.element').tooltip({
html: true,
trigger: 'manual'
}).
on 'mouseenter', ->
clearTimeout window.tooltipTimeout
$(this).tooltip('show') unless $('.tooltip:visible').length > 0
.
on 'mouseleave', ->
_this = this
window.tooltipTimeout = setTimeout ->
$(_this).tooltip('hide')
, 100
$(document).on 'mouseenter', '.tooltip', ->
clearTimeout window.tooltipTimeout
$(document).on 'mouseleave', '.tooltip', ->
trigger = $($(this).siblings('.element')[0])
window.tooltipTimeout = setTimeout ->
trigger.tooltip('hide')
, 100
This solution worked out fine for me: (now its bulletproof) ;-)
function enableThumbPopover() {
var counter;
$('.thumbcontainer').popover({
trigger: 'manual',
animation: false,
html: true,
title: function () {
return $(this).parent().find('.thumbPopover > .title').html();
},
content: function () {
return $(this).parent().find('.thumbPopover > .body').html();
},
container: 'body',
placement: 'auto'
}).on("mouseenter",function () {
var _this = this; // thumbcontainer
console.log('thumbcontainer mouseenter')
// clear the counter
clearTimeout(counter);
// Close all other Popovers
$('.thumbcontainer').not(_this).popover('hide');
// start new timeout to show popover
counter = setTimeout(function(){
if($(_this).is(':hover'))
{
$(_this).popover("show");
}
$(".popover").on("mouseleave", function () {
$('.thumbcontainer').popover('hide');
});
}, 400);
}).on("mouseleave", function () {
var _this = this;
setTimeout(function () {
if (!$(".popover:hover").length) {
if(!$(this).is(':hover'))
{
$(_this).popover('hide');
}
}
}, 200);
});
}
$(function() {
$("[data-toggle = 'popover']").popover({
placement: 'left',
html: true,
trigger: " focus",
}).on("mouseenter", function() {
var _this = this;
$(this).popover("show");
$(this).siblings(".popover").on("mouseleave", function() {
$(_this).popover('hide');
});
}).on("mouseleave", function() {
var _this = this;
setTimeout(function() {
if (!$(".popover:hover").length) {
$(_this).popover("hide")
}
}, 100);
});
});
I found the mouseleave
will not fire when weird things happen, like the window focus changes suddenly, then the user comes back to the browser. In cases like that, mouseleave
will never fire until the cursor goes over and leaves the element again.
This solution I came up with relies on mouseenter
on the window
object, so it disappears when the mouse is moved anywhere else on the page.
This was designed to work with having multiple elements on the page that will trigger it (like in a table).
var allMenus = $(".menus");
allMenus.popover({
html: true,
trigger: "manual",
placement: "bottom",
content: $("#menuContent")[0].outerHTML
}).on("mouseenter", (e) => {
allMenus.not(e.target).popover("hide");
$(e.target).popover("show");
e.stopPropagation();
}).on("shown.bs.popover", () => {
$(window).on("mouseenter.hidepopover", (e) => {
if ($(e.target).parents(".popover").length === 0) {
allMenus.popover("hide");
$(window).off("mouseenter.hidepopover");
}
});
});
It will be more flexible with hover()
:
$(".my-popover").hover(
function() { // mouse in event
$this = $(this);
$this.popover({
html: true,
content: "Your content",
trigger: "manual",
animation: false
});
$this.popover("show");
$(".popover").on("mouseleave", function() {
$this.popover("hide");
});
},
function() { // mouse out event
setTimeout(function() {
if (!$(".popover:hover").length) {
$this.popover("hide");
}
}, 100);
}
)
This is my code for show dynamics tooltips with delay and loaded by ajax.
$(window).on('load', function () {
generatePopovers();
$.fn.dataTable.tables({ visible: true, api: true }).on('draw.dt', function () {
generatePopovers();
});
});
$(document).ajaxStop(function () {
generatePopovers();
});
function generatePopovers() {
var popover = $('a[href*="../Something.aspx"]'); //locate the elements to popover
popover.each(function (index) {
var poplink = $(this);
if (poplink.attr("data-toggle") == null) {
console.log("RENDER POPOVER: " + poplink.attr('href'));
poplink.attr("data-toggle", "popover");
poplink.attr("data-html", "true");
poplink.attr("data-placement", "top");
poplink.attr("data-content", "Loading...");
poplink.popover({
animation: false,
html: true,
trigger: 'manual',
container: 'body',
placement: 'top'
}).on("mouseenter", function () {
var thispoplink = poplink;
setTimeout(function () {
if (thispoplink.is(":hover")) {
thispoplink.popover("show");
loadDynamicData(thispoplink); //load data by ajax if you want
$('body .popover').on("mouseleave", function () {
thispoplink.popover('hide');
});
}
}, 1000);
}).on("mouseleave", function () {
var thispoplink = poplink;
setTimeout(function () {
if (!$("body").find(".popover:hover").length) {
thispoplink.popover("hide");
}
}, 100);
});
}
});
function loadDynamicData(popover) {
var params = new Object();
params.somedata = popover.attr("href").split("somedata=")[1]; //obtain a parameter to send
params = JSON.stringify(params);
//check if the content is not seted
if (popover.attr("data-content") == "Loading...") {
$.ajax({
type: "POST",
url: "../Default.aspx/ObtainData",
data: params,
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function (data) {
console.log(JSON.parse(data.d));
var dato = JSON.parse(data.d);
if (dato != null) {
popover.attr("data-content",dato.something); // here you can set the data returned
if (popover.is(":hover")) {
popover.popover("show"); //use this for reload the view
}
}
},
failure: function (data) {
itShowError("- Error AJAX.<br>");
}
});
}
}
来源:https://stackoverflow.com/questions/15989591/how-can-i-keep-bootstrap-popover-alive-while-the-popover-is-being-hovered