Override popover option parameter with data-attributes

javascript, jquery, popover, twitter-bootstrap, twitter-bootstrap-3

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:

- The plugin defaults

- Then the data-attributes

- 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>

Problem

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?

Original source

Related problems