Search code examples
javascriptjquerytwitter-bootstraptwitter-bootstrap-3popover

Override popover option parameter with data-attributes


I'm initializing Bootstrap's popovers like this:

$(".popovers").popover({
  placement: "right" 
});

Occasionally, I'll want to display a popover in a specific place, so I use a data-placement attribute on that particular element like this:

<i class="popovers fa fa-question-circle"
   data-content="Some popover text." 
   data-placement="bottom" >
</i>

Bootstrap seems to ignore the data-placement attribute and uses the option settings instead.

It seems to me the data-placement attribute should override anything passed to the initialization method. I've scoured the Bootstrap 3 docs and can't find anything that confirms or denies this.

Here's a small demo:

$(".popovers").popover({
  container: "body", 
  trigger: "hover",
  placement: "right" 
});
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css" rel="stylesheet"/>
<link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/js/bootstrap.js"></script>

<div class="container">
  <i class="popovers fa fa-question-circle"
     data-content="Some popover text." 
     data-placement="bottom" 
     data-original-title="">
  </i>
</div>

Is the data-placement attribute ignored when you pass in the property in JavaScript?


Solution

  • To answer your question:

    Is the data-placement attribute ignored when you pass in the property in JavaScript?

    Yes - Here's a snippet from tooltip.js:

    Tooltip.prototype.getOptions = function (options) {
        options = $.extend({}, this.getDefaults(), this.$element.data(), options)
    

    You'll see that when creating the options for each tooltip (from which popover inherits), Bootstrap calls jQuery's extend which combines the following objects in this exact order:

    1. The plugin defaults
    2. Then the data-attributes
    3. And finally the passed in options object

    Solution

    To change this, we can override the GetOptions function using the Programmatic API and reversing the order of operations:

    $.fn.popover.Constructor.prototype.getOptions = function (options) {
    
      options = $.extend({}, this.getDefaults(), options, this.$element.data())
    
      if (options.delay && typeof options.delay == 'number') {
        options.delay = {
          show: options.delay,
          hide: options.delay
        }
      }
    
      return options
    }
    

    Additionally, we can maintain a little less code by pre-merging the options and the element data and then passing that back to the original function to override both so we don't have to spell out the entire function

    var _getOptionsOriginal = $.fn.popover.Constructor.prototype.getOptions
    
    $.fn.popover.Constructor.prototype.getOptions = function (options) {
      options = $.extend({}, options, this.$element.data())
      return _getOptionsOriginal.call(this, options);
    }
    

    Here's a Demo in Stack Snippets:

    var _getOptionsOriginal = $.fn.popover.Constructor.prototype.getOptions
    
    $.fn.popover.Constructor.prototype.getOptions = function (options) {
      options = $.extend({}, options, this.$element.data())
      return _getOptionsOriginal.call(this, options);
    }
    
    $("[data-toggle='popover']").popover({placement: 'bottom'})
    <link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css" rel="stylesheet"/>
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/js/bootstrap.js"></script>
    
    <div class="container" >
    
      <h2>Popovers</h2>
    
      <button type="button" class="btn btn-default" 
              data-container="body" data-toggle="popover" 
              data-placement="right" data-content="Vivamus sagittis">
        Popover on Right - Data Attribute
      </button>
      <br/><br/>
      <button type="button" class="btn btn-default" 
              data-container="body" data-toggle="popover" 
              data-content="Vivamus sagittis">
        Popover on Bootom - Option
      </button>
    
    </div>