Hailwood
Hailwood

Reputation: 92581

Attach event handler to button in twitter bootstrap popover

I am using the twitter bootstrap popovers,

In the popover I am adding a button,

I need to attach a click handler to the button, but the way popover works is each time it shows it removes and re-creates the element, instead of just showing/hiding it, hence removing any event handlers I have associated with said button.

I am creating several popovers all with their own version of the button, so just applying a class to the popover won't work (unless I generate a different class for each one :/), the button may or may not have it's own ID, so cannot apply an ID.

How can I apply a event handler to something in the contents of the twitter bootstrap popover?

Upvotes: 26

Views: 36299

Answers (7)

mrtn
mrtn

Reputation: 353

Very simple solution that worked for me is:

// suppose that popover is defined in HTML
$('a.foo').popover(); 

// when popover's content is shown
$('a.foo').on('shown.bs.popover', function() {
    // set what happens when user clicks on the button
    $("#my-button").on('click', function(){
        alert("clicked!!!");
    });
});

// when popover's content is hidden
$('a.foo').on('hidden.bs.popover', function(){
    // clear listeners
    $("#my-button").off('click');
});

Why this works: Basically popover's content has no listener until the popover is opened.

When popover is shown, bootstrap fires its event shown.bs.popover. We can attach an event handler on this event to $(a.foo) using the jQuery on method. So when popover is shown, the handler (callback) function is called. In this callback, we can attach event handlers to the content of the popover - for example: what happens when user clicks on this button inside the popover.

After popover is closed, it is good idea to remove all attached handlers to the popover's content. This is done via hidden.bs.popover handler, which removes handlers with jQuery .off method. This prevents event handlers inside the popover to be called twice (and more) when the popover is opened again...

Upvotes: 11

Patrik Simek
Patrik Simek

Reputation: 1048

You can get into trouble if you add more complex structure in popover's content, for example an external component. For this case, this should do the trick.

var content = $('<button>Bingo?</button>');
content.on('click', function() {
    alert('Bingo!')
});

$('a.foo').popover({
    html: true,
    content: content
}).on('hidden.bs.popover', function() {
    content.detach(); # this will remove content nicely before the popover removes it
});

Upvotes: 1

smingers
smingers

Reputation: 101

Just to slightly update DashK's very good answer: .delegate() has been superseded by .on() as of jQuery 1.7 (see here).

$('a.foo').popover({
    html: true,
    title: 'Hello',
    placement: 'bottom',
    content: '<button id="close-me">Close Me!</button>'
}).parent().on('click', 'button#close-me', function() {
    console.log('World!');
});

See jsfiddle here: http://jsfiddle.net/smingers/nCKxs/2/

I have also had some issues with chaining the .on() method to $('a.foo'); if you experience such an issue, try adding it to the document, body, or html, e.g.:

$('a.foo').popover({
    html: true,
    title: 'Hello',
    placement: 'bottom',
    content: '<button id="close-me">Close Me!</button>'
});

$('body').on('click', 'button#close-me', function() {
    console.log('World!');
});

Upvotes: 10

Sandeep
Sandeep

Reputation: 29341

$('.btn-popover').parent().delegate('button#close-me','click', function(){
  alert('Hello');
});

If data attributes are set in static html the above method works fine. Thanks :)

Upvotes: 1

wahhzu
wahhzu

Reputation: 1

try this

var content = function() {
    var button = $($.parseHTML("<button id='foo'>bar</button>"));
    button.on('click', '#foo', function() {
        console.log('you clicked me!');
    } );
    return button;
};

$( '#new_link' ).popover({
    "html": true,
    "content": content,
});

Upvotes: 0

DashK
DashK

Reputation: 2670

I had the same problem, and, in my case, the $(body).on('click') workaround won't work, since the application has lotta click buttons.

I did the following instead. This way, we can limit the scope of the delegate event to just the parent of the popover element.

$('a.foo').popover({
    html: true,
    title: 'Hello',
    placement: 'bottom',
    content: '<button id="close-me">Close Me!</button>'
}).parent().delegate('button#close-me', 'click', function() {
    console.log('World!');
});

JS Fiddle: http://jsfiddle.net/dashk/5Yz7z/

P.S. I used this technique in within a Backbone.View in my application. Here's the snippet of the code in Fiddle, in case you're using this in Backbone.js as well...: http://jsfiddle.net/dashk/PA6wY/

EDITED In Bootstrap 2.3, you can specify a target container which popover will be added to. Now, instead of doing the .parent() locator, you can also listen to events specifically to the container... This can make the listener even more specific (Imagine creating a DIV that only exists to contain the popover.)

Upvotes: 36

manishie
manishie

Reputation: 5322

This should do it. This will take care of any existing and future button elements created inside an element with the .popover class:

$('body').on('click', '.popover button', function () {
    // code here
});

Upvotes: 28

Related Questions