2

Following this example, i tried to implement a hidden callback function but while show callback works perfectly, there's no way to make hidden callback work. Can someone explain why this happens?

I've created this fiddle to replicate the problem.

$(document).ready(function() {
  var showCb = $.fn.popover.Constructor.prototype.show;
  $.fn.popover.Constructor.prototype.show = function () {
    showCb.call(this);
    if (this.options.showCb) {
      this.options.showCb();
    }
  }
  
  var hiddenCb = $.fn.popover.Constructor.prototype.hidden;
  $.fn.popover.Constructor.prototype.hidden = function () {
    hiddenCb.call(this);
    if (this.options.hiddenCb) {
      this.options.hiddenCb();
    }
  }
  
  $("[data-toggle=popover]").popover({
    showCb: function() {
      alert('showCb');
    },
    hiddenCb: function() {
      alert('hiddenCb');
    }
  });
})
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>

<div class="container">
  <h3>Popover Example</h3>
  <a href="#" data-toggle="popover" title="Popover Header" data-content="Some content inside the popover">Toggle popover</a>
</div>

UPDATE

I've created a new jsFiddle to show Christos's second snippet applied to Bootstrap's jQBTK plugin. This plugin takes advantage of Bootstrap's Popovers to create a virtual keyboard. Problem: events are bind to the dynamically created object and so they fires multiple times. How can this be optimized?

Mark
  • 645
  • 2
  • 9
  • 27
  • Did you try my updated answer if it's working? – Christos Lytras Mar 05 '20 at 20:01
  • @ChristosLytras partially...I started testing yesterday evening and in my page the click trigger seems to be not working, there must be some conflict with other click events configured...so I managed just now to make it work with the manual trigger. – Mark Mar 06 '20 at 08:17

1 Answers1

0

At hiddenCb the prototype function is named hide and not hidden like you have in your code, so $.fn.popover.Constructor.prototype.hidden have to be $.fn.popover.Constructor.prototype.hide.

These prototype functions are the methods of the popover and not the events. There is a method .popover('hide') but there is no method hidden. Your code is working because popover calls the methods show and hide and not by firing the events.

The code you found is actually a hack that hooks/changes default show and hide methods to trigger your functions along with the popover default code, which is not so ideal when you want to handle these events.

To make it work in your code, change hidden method to hide:

$(document).ready(function() {
  var showCb = $.fn.popover.Constructor.prototype.show;
  $.fn.popover.Constructor.prototype.show = function () {
    showCb.call(this);
    if (this.options.showCb) {
      this.options.showCb();
    }
  }
  
  var hiddenCb = $.fn.popover.Constructor.prototype.hide;
  $.fn.popover.Constructor.prototype.hide = function () {
    hiddenCb.call(this);
    if (this.options.hiddenCb) {
      this.options.hiddenCb();
    }
  }
  
  $("[data-toggle=popover]").popover({
    showCb: function() {
      alert('showCb');
    },
    hiddenCb: function() {
      alert('hiddenCb');
    }
  });
})
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>

<div class="container">
  <h3>Popover Example</h3>
  <a href="#" data-toggle="popover" title="Popover Header" data-content="Some content inside the popover">Toggle popover</a>
</div>

However, if you want to properly handle show.bs.popover, shown.bs.popover, hide.bs.popover and hidden.bs.popover events, then you should do it by using on and much simpler code like this:

$(document).ready(function() {
  $("[data-toggle=popover]")
    .popover()
    .on('shown.bs.popover', function() {
      alert('showCb!');
    })
    .on('hidden.bs.popover', function () {
      alert('hiddenCb!');
    });
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>

<div class="container">
  <h3>Popover Example</h3>
  <a href="#" data-toggle="popover" title="Popover Header" data-content="Some content inside the popover">Toggle popover</a>
</div>

UPDATE

For jQBTK you just use click trigger and then use the events. That will trigger each shown/hidden events only once:

$('input').keyboard({
  trigger: 'click',
})
.on('shown.bs.popover', function() {
  console.log('shownCb!');
})
.on('hidden.bs.popover', function () {
  console.log('hiddenCb!');
});

Check this working jsFiffle.

Christos Lytras
  • 36,310
  • 4
  • 80
  • 113
  • Thanks for your help. I'm still having troubles. I've update the question with another jsFiddle showing your second snippet applied to jQBTK Bootstrap's plugin. Could you please take a look at it? – Mark Feb 29 '20 at 12:37
  • @Mark you haven't mention anywhere in your question anything about [jQBTK](https://github.com/mafu-d/jqbtk), your question is *"Bootstrap 3 popover callback on hidden event not working"* and I think I answered that why your code didn't work. So to answer your second question, why jQBTK isn't working, it's because it doesn't bind any events to `popover`, you have to alter the code of it **or use the first method you found** using `$.fn.popover.Constructor.prototype.show` and `$.fn.popover.Constructor.prototype.hide`. Isn't that work for you now using `hide` instead of `hidden`? – Christos Lytras Feb 29 '20 at 15:13
  • I didn't mention it because I was trying to simplify the situation. In first fiddle I was using the plain popover plugin and was experimenting problem already there so I asked the question about popover, not about jQBTK. By the way, first code you are suggesting to use have the same problem that I'm reporting in the question update: callbacks are being stacked and called multiple times (the more popover I open, the more callbacks are being called...dismitting popover does not dismit the callback). – Mark Feb 29 '20 at 19:29
  • When you have a problem, you must describe the whole problem **with simplified code** and not break/mention a part of it **that you think** it's the culprit. Your updated request *"How can this be optimized?"* is unclear of **what you're asking**, **what your problem is** and **what you want to achieve**. – Christos Lytras Feb 29 '20 at 20:55
  • In my opinion is everything there and I don't know how else to explain: i'm asking a way to catch a hidden callback on a popover, my problem is (using your suggestion) that callbacks are being stacked and called several times at once, i want to achieve what I'm asking. I'm not english native but if there's a specific point unclear, tell me what it is and I try to explain better. – Mark Mar 01 '20 at 09:33
  • @Mark the suggestion is yours, is not mine. You had a problem and you found [this](https://stackoverflow.com/questions/14694930/callback-function-after-tooltip-popover-is-created-with-twitter-bootstrap) hooking `$.fn.popover.Constructor.prototype.show` and `$.fn.popover.Constructor.prototype.hidden` and your problem **at first** was *"Bootstrap 3 popover callback on hidden event not working"*. I gave a complete answer on why it wasn't working and gave you a solution and a *proper* way to do what your question describes. Then you changed the question and **you added a problem about jQBTK**. – Christos Lytras Mar 01 '20 at 10:07
  • @Mark I wouldn't do that in other cases, but I understand that you may have some trouble using English language and again you're not so experienced Stackoverflow user. English is not my native language either and I can understand you. So, I have updated my answer with a working code for **jQBTK** that it triggers the `shown`/`hidden` events only once. There is also a working jsFiddle, check it out. – Christos Lytras Mar 01 '20 at 10:52