How to bind bootstrap popover on dynamic elements - javascript

I'm using Twitter Bootstrap's popover on the dynamic list. The list item has a button, when I click the button, it should show up popover. It works fine when I tested on non-dynamic.
this is my JavaScript for non-dynamic list
$("button[rel=popover]").popover({
placement : 'right',
container : 'body',
html : true,
//content:" <div style='color:red'>This is your div content</div>"
content: function() {
return $('#popover-content').html();
}
})
.click(function(e) {
e.preventDefault();
});
However, It doesn't work well on dynamic list. It can show up when I click the button "twice" and only show up one of list items I click fist time.
MY html:
<ul id="project-list" class="nav nav-list">
<li class='project-name'>
<a >project name 1
<button class="pop-function" rel="popover" ></button>
</a>
</li>
<li class='project-name'>
<a>project name 2
<button class="pop-function" rel="popover" ></button>
</a>
</li>
</ul>
<div id="popover-content" style="display:none">
<button class="pop-sync"></button>
<button class="pop-delete"></button>
</div>
My JavaScript for dynamic:
$(document).on("click", "#project-list li" , function(){
var username = $.cookie("username");
var projectName = $(this).text()
$("li.active").removeClass("active");
$(this).addClass("active");
console.log("username: " +username + " project name: "+projectName );
});
$(document).on("click", "button[rel=popover]", function(){
$(this).popover({
placement : 'right',
container : 'body',
html : true,
content: function() {
return $('#popover-content').html();
}
}).click(function(e){
e.preventDefault();
})
});
//for close other popover when one popover button click
$(document).on("click", "button[rel=popover]" , function(){
$("button[rel=popover]").not(this).popover('hide');
});
I have searched similar problems, but I still can't find the one to solve my problem. If anyone has some ideas, please let me know. Thanks your help.

Update
If your popover is going to have a selector that is consistent then you can make use of selector property of popover constructor.
var popOverSettings = {
placement: 'bottom',
container: 'body',
html: true,
selector: '[rel="popover"]', //Sepcify the selector here
content: function () {
return $('#popover-content').html();
}
}
$('body').popover(popOverSettings);
Demo
Other ways:
(Standard Way) Bind the popover again to the new items being inserted. Save the popoversettings in an external variable.
Use Mutation Event/Mutation Observer to identify if a particular element has been inserted on to the ul or an element.
Source
var popOverSettings = { //Save the setting for later use as well
placement: 'bottom',
container: 'body',
html: true,
//content:" <div style='color:red'>This is your div content</div>"
content: function () {
return $('#popover-content').html();
}
}
$('ul').on('DOMNodeInserted', function () { //listed for new items inserted onto ul
$(event.target).popover(popOverSettings);
});
$("button[rel=popover]").popover(popOverSettings);
$('.pop-Add').click(function () {
$('ul').append("<li class='project-name'> <a>project name 2 <button class='pop-function' rel='popover'></button> </a> </li>");
});
But it is not recommended to use DOMNodeInserted Mutation Event for performance issues as well as support. This has been deprecated as well. So your best bet would be to save the setting and bind after you update with new element.
Demo
Another recommended way is to use MutationObserver instead of MutationEvent according to MDN, but again support in some browsers are unknown and performance a concern.
MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
// create an observer instance
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
$(mutation.addedNodes).popover(popOverSettings);
});
});
// configuration of the observer:
var config = {
attributes: true,
childList: true,
characterData: true
};
// pass in the target node, as well as the observer options
observer.observe($('ul')[0], config);
Demo

Probably way too late but this is another option:
$('body').popover({
selector: '[rel=popover]',
trigger: 'hover',
html: true,
content: function () {
return $(this).parents('.row').first().find('.metaContainer').html();
}
});

I did this and it works for me.
"content" is placesContent object. not the html content!
var placesContent = $('#placescontent');
$('#places').popover({
trigger: "click",
placement: "bottom",
container: 'body',
html : true,
content : placesContent,
});
$('#places').on('shown.bs.popover', function(){
$('#addPlaceBtn').on('click', addPlace);
}
<div id="placescontent"><div id="addPlaceBtn">Add</div></div>

Try this HTML
Do Popover 1
Do Popover
<div id="popover-content-1" style="display: none">Content 1</div>
<div id="popover-content-2" style="display: none">Content 2</div>
jQuery:
$(function() {
$('[data-toggle="popover"]').each(function(i, obj) {
var popover_target = $(this).data('popover-target');
$(this).popover({
html: true,
trigger: 'focus',
placement: 'right',
content: function(obj) {
return $(popover_target).html();
}
});
});
});

This is how I made the code so it can handle dynamically created elements using popover feature. Using this code, you can trigger the popover to show by default.
HTML:
<div rel="this-should-be-the-target">
</div>
JQuery:
$(function() {
var targetElement = 'rel="this-should-be-the-target"';
initPopover(targetElement, "Test Popover Content");
// use this line if you want it to show by default
$(targetElement).popover('show');
function initPopover(target, popOverContent) {
$(target).each(function(i, obj) {
$(this).popover({
placement : 'auto',
trigger : 'hover',
"html": true,
content: popOverContent
});
});
}
});

Just to update that, a no-jquery answer for people using bootstrap 5 is
var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'))
popoverTriggerList.map(function (popoverTriggerEl) {
return new bootstrap.Popover(popoverTriggerEl, {
content: get_content
})
})
The get_content function should use this (the popover element) to generate dynamic content.

Related

Show and hide a popover on click of div's

Here is my jsfiddle: My fiddle
After drag n drop of "rule/event" class into "layout" class, how to create a popover with HTML form on-click or double-click of the dropped components?
$('[rel="popover"]').popover({
alert("hi");
container: 'body',
html: true,
content: function () {
var clone = $($(this).data('popover-content')).clone(true).removeClass('hide');
return clone;
}
}).click(function(e) {
e.preventDefault();
});

Boostrap - Popover only being fired after second click

I addClass/removeClass a CSS class called SiteClass dynamically (see this question for background). I bind a bootstrap popover to these like so:
$(document).ready(function(){
$("#SiteList").on('click','a.SiteClass', function(e){
alert('clicked');
e.preventDefault();
e.stopPropagation();
var strcontent = $(this).html();
var strTitle = 'Title for ' + strcontent;
var strMessage = 'Foo <b>Bar</b> Baz';
$(this).popover({
html: true,
title: strTitle,
content: strMessage
});
});
});
The first time I click I get the alert box 'clicked', but no popover. Subsequent clicks and the popover works.
Any clue as to why this is happening and to get the popover to fire from click 1?
$().popover(options) simply initializes your popover. You can trigger the display of the popover with:
$(this).popover('show');
If you would like to toggle the popover on click instead, try:
$(this).popover('toggle');
I think the reason it works only after the first click in your case is that with the first click the popover is initialized with the default trigger 'click', so that subsequent clicks (but not the first click) will trigger it.
after a lot of tries finally I have found out this solution and working fine:
<script>
$(document).ready(function () {
$(document).on("click", '#add-new', function (e) {
e.preventDefault();
$('#add-new').popover({
placement: 'right',
html: true,
container: 'body',
trigger: 'manual',
content: function () {
return $('#popover_content_wrapper').html();
},
});
$(this).popover('toggle');
});
});
</script>

Bootstrap 3.1.1 Popover Delegated OK Function

I have a table and last column has a button generated Dynamically.
<button id="popover-row' + row + '" rel="popover">' + docAccessText + ' ' + fileAccessText + '</Button>;
I am creating a Dynamic Popover on click of the Above Button.
// initialize the Popover
var popOverSettings = {
placement: 'bottom',
container: 'body',
html: true,
selector: '[rel="popover"]',
content: $('#permissionPopover').html()
}
// bind the popover on body
$("body").popover(popOverSettings).parent().delegate('button.btn_permission_ok', 'click', function(event) {
// Do something on click of OK
$("[rel=popover]").popover("destroy");
$(".popover").remove();
}
}).on("show.bs.popover", function(e) {
// hide all other popovers before showing the current popover
$("[rel=popover]").not(e.target).popover("destroy");
$(".popover").remove();
}).on("shown.bs.popover", function(e) {
// Do something after showing the popover
});
// click on cancel button removes the popover
$("body").popover(popOverSettings).parent().delegate('div.btn_permission_cancel', 'click', function() {
$("[rel=popover]").popover("destroy");
$(".popover").remove();
});
Everything works as expected, but only the first time. When i open this view again, things start duplicating. Popover functions start executing twice. If I close the view again, now popover functions start executing thrice.
I believe that when I am destroying the PopOver on Click of Delegated OK, The events are still there. I tried the below line of code to undelegate the event, but it's not working.
$(event.target).parent().undelegate('button.btn_permission_ok', 'click');
Please suggest.
Not a complete answer, but if you would like one popover per button to be triggered on the button, try using some code like this.
var popOverSettings = {
trigger: 'manual',
placement: 'bottom',
container: 'body',
html: true,
content: $('#permissionPopover').html()
};
$(document).on("click", "button[rel='popover']", function(e) {
var $btn = $(this);
$btn.popover(popoverOptions);
$btn.popover("show");
});

Different Behaviors for Touch and Click

I'm using Bootstrap Popovers to supply "help text" in my UI.
My existing JavaScript:
// add "tooltips" via popover
$('[data-toggle="popover"]').popover({
container: 'body',
trigger: 'hover',
placement: 'auto bottom'
});
The Popover displays when I hover with a mouse or touch the element. My problem is with anchor tag elements. If the Popover is triggered by a touch event:
Don't follow the link
Add an anchor tag element to the Popover text to give access to the underlying link
I'd detect whether the user is on a touch device, then serve different content from data attributes. Use Popover methods to trigger your various actions.
<a href="#"
data-href="http://jsfiddle.net"
data-toggle="popover"
title="A popover title"
data-hover-content="No link here."
data-touch-content="<a href='http://jsfiddle.net'>
A link here</a>.">A popover link
</a>
var is_touch_device = 'ontouchstart' in document.documentElement;
$('[data-toggle="popover"]').popover({
container: 'body',
trigger: 'manual',
placement: 'auto bottom',
html: true,
content: function () {
if (is_touch_device) {
return $(this).attr('data-touch-content');
} else {
return $(this).attr('data-hover-content');
}
}
})
.on('mouseenter touch', function (e) {
$(this).popover('show');
})
.on('mouseleave', function () {
$(this).popover('hide');
})
.on('click', function () {
if (!is_touch_device) {
window.location.href = $(this).attr('data-href');
}
});
Fiddle demo
This can probably be simplified a bit. You could specify your content in the content function instead, of course.
this might help:
event.preventDefault()
"Description: If this method is called, the default action of the event will not be triggered... For example, clicked anchors will not take the browser to a new URL..."

Manipulating original elements with qTip

I have a bunch of divs on my page and each of them has only the class attribute. In the divs there are some spans, which are set up to display a tooltip with the help of qTip.
The tooltip should contain three items:
Up: anchor, which should move the OuterDiv up (probably something like this: move up/down in jquery)
Down: anchor, which should move the OuterDiv down
Delete: anchor, which should remove the calling OuterDiv
My code so far:
<body>
<div class="OuterDiv">
<div class="InnerDiv">
<span class="Position">Position 1</span>
</div>
</div>
<div class="OuterDiv">
<div class="InnerDiv">
<span class="Position">Position 2</span>
</div>
</div>
</body>
And scripts:
$(document).ready(function () {
var qTipContent = '↑ ';
qTipContent = qTipContent + '↓ ';
qTipContent = qTipContent + 'X';
$('.Position').each(function () {
$(this).qtip({
content: qTipContent,
hide: {
fixed: true
}
})
});
});
How should the onclick function in the qTip content look like?
My solution can be found at this jsFiddle - Besides cleaning up the qTipContent (was just really messy), the only real notable addition was adding ids to the anchors, and using the qTip api to add bindings to the click event for each anchor as the qTip window is added.
$('.Position').each(function(idx, elem) {
$(this).qtip({
content: qTipContent,
show: {
when: {
event: 'click'
}
},
hide: {
fixed: true,
when: {
event: "unfocus"
}
},
api: {
onRender: function() {
var $qtip = $(this.elements.content);
var odiv = $(elem).closest(".OuterDiv");
$("#up_arrow", $qtip).click(function() {
odiv.insertBefore(odiv.prev());
})
$("#down_arrow", $qtip).click(function() {
odiv.insertAfter(odiv.next());
})
$("#delete", $qtip).click(function() {
odiv.remove();
})
}
}
})
});

Categories