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