Dhaulagiri
Dhaulagiri

Reputation: 3291

Close all open Bootstrap popovers created via delegation

I have a scenario with Bootstrap Popovers (version 2.3 although I can recreate the issue in 3 as well) where I have multiple popovers on the page and I want to be able to close any open popovers when a new one is opened.

The method I have (taken from here) to close open popovers works fine until I initialize my popovers using the selector option which delegates the popover objects.

Here's the JS:

// Works if popovers are instantiated this way
//$("[data-toggle=popover]").popover();

// Doesn't work if popovers are instantiated this way
var options = { selector: '[data-toggle=popover]' };

$(".container").popover(options)

$("[data-toggle=popover]").click(function() {
    $("[data-toggle=popover]").not(this).popover('hide');
});

And the HTML:

<div class="container">
    <a href="#" class="btn btn-large btn-danger" data-toggle="popover" title="" data-placement="bottom" data-content="And here's some amazing content. It's very engaging. right?" data-original-title="Popover Title">Click to see my popover.</a>
    <a href="#" class="btn btn-large btn-danger" data-toggle="popover" title="" data-placement="bottom" data-content="And here's some amazing content. It's very engaging. right?" data-original-title="Popover Title">Click to see my popover.</a>
</div>

Bootply example

I've spent some time digging through the source code and I see what the issue might be, but I'm not sure how to work around this. Has anyone made something like this work before?

Update:

This does work - $("[data-toggle=popover]").filter(this).popover('show'); - My only concern is this block of code from the popover library:

function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.popover')
      var options = typeof option == 'object' && option

      if (!data && option == 'destroy') return
      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

The line

if (!data) $this.data('bs.popover', (data = new Popover(this, options)))

adds a data attribute to .container when the popover is init'ed initially using the selector option, but then when

$("[data-toggle=popover]").not(this).popover('hide');

is called it loops through each element that matches the $("[data-toggle=popover]") selector and re-inits a popover on each element it finds, ignoring the fact that a popover object was already added to the parent container and set to work via delegation using the selector option. Is there any way to avoid this?

Upvotes: 0

Views: 580

Answers (2)

Ramy Nasr
Ramy Nasr

Reputation: 2537

The easiest and - in my opinion - the best way to do that, is to use <button> instead of <a> and then use the focus trigger.

var options = { selector: '[data-toggle=popover]', trigger: 'focus' };

$(".container").popover(options);



<div class="container">
    <button class="btn btn-large btn-danger" data-toggle="popover" title="" data-placement="bottom" data-content="And here's some amazing content. It's very engaging. right?" data-original-title="Popover Title">Click to see my popover.</button>
    <button class="btn btn-large btn-danger" data-toggle="popover" title="" data-placement="bottom" data-content="And here's some amazing content. It's very engaging. right?" data-original-title="Popover Title">Click to see my popover.</button>
</div>

Here is a bootply

If you don't want/can't change the anchors, you can try that:

var options = { selector: '[data-toggle=popover]' };

$("body").popover(options)

$("[data-toggle=popover]").on('shown.bs.popover', function(e) {
  $(this).addClass('shown');
});

$("body").on('click', '[data-toggle=popover]', function(e) {
   $('.shown').not(this).popover('hide').removeClass('shown');
});

Here is another bootply.

Upvotes: 2

Kayce Basques
Kayce Basques

Reputation: 25957

Your Javascript hides the other popovers just fine... but you forgot to open the new one!

var options = { selector: '[data-toggle=popover]' };

$(".container").popover(options);

$("[data-toggle=popover]").click(function() {
    $("[data-toggle=popover]").not(this).popover('hide');
    $("[data-toggle=popover]").this.popover('show');
});

Disclosure: I actually don't know what I'm doing, but when I checked the Bootstrap documentation and ran this in Bootply it appears to create the behavior you are looking for.

Bootply

Upvotes: 0

Related Questions