Follow Up Post: Hiding All But The Current Bootstrap Popover

jQuery , Twitter Bootstrap Add comments

Last year around this same time, I published a blog post about a technique I developed for creating multiple Twitter Bootstrap popovers.  I came up with the technique while building a page containing several icons that, when hovered over with the mouse, would display different Bootstrap popovers with explanatory text and HTML.

The other day, a commenter on the original post asked how he could use my technique but ensure that only one popover was open at any given time (which I took to mean that on his page the popovers were triggered by a mouse click rather than a hover).  I gave him a brief, general idea of how to approach it (off the top of my head) but he wasn't clear on what I meant, so I decided to do a post on it.

First off, the options/API for configuring popovers in Bootstrap (currently Bootstrap version 2.3.2) have changed since last year.  Of particular note:

  • The default triggering event used to be hover...at least I assume so, since my original Javascript code didn't specify the triggering mechanism in the popover options.  The default trigger event is now the click event, with the possible options being "click", "hover", "focus", and "manual."

  • By default, the popover function will render the title and content of the popover as plain text:  any HTML markup included in either will be visible as text to the user and have no effect.  Specifically setting the "html" option to true will allow you to use markup in the title and content.  This change in the API was made to protect against cross-site scripting (XSS) attacks.

So solving the commenter's issue - making sure only one popover is displayed at any given time - means hiding all of the other popovers on the page:  if Popover A is opened via click, and then the user clicks on the DOM element that opens Popover B, Popover A needs to vanish. 

Unfortunately, the popover function doesn't provide a callback function:  if it did I could have used that to run the code that hides the other popovers.  So I needed to write code to manually handle the triggering of the current popover.

Using the Javascript code in my previous post as my starting point, and taking the API changes into account, here is the solution I came up with:

$(".pop").each(function() {
    var $pElem= $(this);
    $pElem.popover(
        {
            html: true,
            trigger: 'manual',
            title: getPopTitle($pElem.attr("id")),
            content: getPopContent($pElem.attr("id"))
        }
    );
});
						
$(".pop").click(function() {
    var $pElem= $(this);
    $(".pop").each(function() {
        $currentPop= $(this);
        if($currentPop.prop("id") != $pElem.prop("id")) {
            $currentPop.popover('hide');
        } 
    });
    $pElem.popover('show');
});
				
function getPopTitle(target) {
    return $("#" + target + "_content > div.popTitle").html();
};
		
function getPopContent(target) {
    return $("#" + target + "_content > div.popContent").html();
};

I still used the each() function to initialize each DOM element that triggers a popover (identified with the "pop" class), but I set the trigger option to "manual". Then I wrote a click event handler for those elements that would close all the other popovers before opening the popover for the DOM element the user clicked on.

6 responses to “Follow Up Post: Hiding All But The Current Bootstrap Popover”

  1. Erick Riva Says:
    did not understand the final part "getPopTitle (target)", why (target)?
    Sorry, I understand only some jquery.
  2. Brian Swartzfager Says:
    @Erick: "target" is the name I choose to use for the id parameter that gets passed to the getPopTitle() function. That id value is used to reference the particular block of HTML that holds the title and content I want to appear in the popover (if you refer back to the second block of code in the original post, that's the HTML I'm using to set up the title and content for the different popovers on the page).
  3. Erick Riva Says:
    Please look this link to understand what i need:
    http://redesocial.p.ht/?url=/contacts
    user and pass: admin
    I have a popover that opens with the hover effect and closes with a click out, but need to close one to open another, it opens many every time.
  4. Erick Riva Says:
    i have fixed this issue with the following code:

    $(document).ready(function() {
    $('[rel=popover]').popover({
    trigger: 'hover',
    html: true
        }).click(function (e) {
    e.preventDefault();
    $(this).popover('show');
    });
    // i use http://benalman.com/projects/jquery-outside-events-plugin/ here...
        $("[rel=popover]").bind("clickoutside", function(event){
           $(this).popover('hide');
    });
    });
  5. Martin Says:
    Hello

    How would you change your code to add delay to the popover on hover of element?

    I've been trying setTimeout but doesn't work

    .on("mouseenter", function () {

    var _this = this;
    setTimeout(function(){
    $(this).popover("show");}, 700);
  6. Martin Says:
    Sorry more context

    var tmp = null;
    $(".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,
    placement: function (context, source) {
    var position = $(source).position();
    if (position.left > 615) {
    return "left";
    }
    if (position.left < 615) {
    return "right";
    }
    }
    }
    );
    }).on("mouseenter", function () {

    var _this = this;

    $(this).popover("show");
    $(".popover").on("mouseleave", function () {
    $(_this).popover('hide');
    });
    $(".popover").on("click", 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();
    };

Leave a Reply