Executing functions BEFORE Bootstrap popover is displayed? - javascript

I've recently started using Twitter's new Bootstrap 2.0.1 and its Javascript popovers.
I want to write a script so that no more than one popover can be displayed at one time. In other words, when a new popover is generated for whatever reason (e.g. the client clicks or hovers over a new element with a popover), all of the PREVIOUSLY displayed popovers are hidden first.
Here's the function that initially sets up all of the popovers for my webpage:
$(function (){
$("[rel=popover]").popover({placement:'left', trigger:'click', html:true});
});
What I need, I think, is to write a function that hides all popovers. I would call that function BEFORE displaying every popover, to ensure that only one popover is displayed at a time. The function might look like this, I imagine:
function hidePopovers(){
$(function (){
$("[rel=popover]").popover('hide');
});
}
But my problem is figuring out WHERE (or HOW) to call this hidePopovers function. I want to call it when a popover is triggered, but before the popover is displayed. Help?
Oh, and just to clear up any confusion, the new Bootstrap now has a 'click' trigger that allows you to display popovers upon clicking. More details about it can be found here.
Thank you so much!

Considering what you have presented as the problem to solve, I think that it would be much more efficient to simply store a reference to the last popover open, rather than execute the hide() method on every single popover element you might select on the page. As far as I understand it, you only want a single popover to be open in the first place, so there should only ever be at most a single one to hide.
The following would do the trick:
var $visiblePopover;
$('body').on('click', '[rel="popover"]', function() {
var $this = $(this);
// check if the one clicked is now shown
if ($this.data('popover').tip().hasClass('in')) {
// if another was showing, hide it
$visiblePopover && $visiblePopover.popover('hide');
// then store reference to current popover
$visiblePopover = $this;
} else { // if it was hidden, then nothing must be showing
$visiblePopover = '';
}
});​
JSFiddle
Technically, you could potentially change the selector where the delegate handler is attached (in the example code 'body' is used) to a more specific element of the page, allowing you to attach the only-one-visible-at-a-time behavior to only a subset of the popovers on the page.
For instance, if you had a specific form where the popovers would appear too close together, but other popups on the page wouldn't collide/overlap, you could select just the form (e.g., '#some_form_id'), and only the popups in the form would have the behavior.
JSFiddle
Note: In this latter example, I also optimized the code a bit by changing the stored reference to only use the actual Popover object, rather than the jQuery-ized DOM element it is attached to.

Haven't tested this but something like this might work:
Set the trigger to manual.
Listen for click events and on click, call hidePopovers(), and then show the clicked popover.
$(function (){
function hidePopovers(){
$(function (){
$("[rel=popover]").popover('hide');
});
}
$("[rel=popover]").popover({placement:'left', trigger:'manual', html:true});
$("[rel=popover]").click(function() { hidePopovers(); $(this).popover('show');});
});

Related

jQuery toggle on click out

I have a series of spans (togglers) and a series of divs (toggled). I created a make_toggle function that receives the toggler and its corresponding toggled as arguments.
Everything seems to work kind of ok up to the point where I try to implement a "toggle on click out". What I've tried is to attach to the html click event a function that checks whether the target of the click is contained within the toggled element. On toggle "back", I would then detach the handler so I am only checking when I need.
var check_if_clickingout = function(e) {
if (!toggled[0].contains(e.target)) {
toggle();
}
};
See fiddle: https://jsfiddle.net/andinse/65o211nc/11/
It doesn't even seem to work anymore but when it used to, it was triggering many more times than necessary (which was the reason for me to come here ask for help).
What am I doing wrong? What is the most effective way to go about this kind of situation where I am giving functionality to a series of independent DOM elements?
Just putting this out here that this seems to do the same thing.
$("span").click(function() {
$(this).siblings("div").toggleClass("blue");
});
Maybe I am missing something more that I am not seeing in your example.
See more: http://api.jquery.com/toggleclass/

Hide Bootstrap Popover if parent element is removed

How do you hide a bootstrap popover if the parent element, that triggered this popover, is removed from the dom?
If a user clicks a button on my page, some content will be loaded into a div via ajax. On the next click on a different button, another ajax call will replace the content in this same div.
The content loaded into this div contains elements that act as Bootstrap Popover triggers, like this one:
<a class="infolink" data-toggle="popover" data-title="some title" data-placement="bottom" data-trigger="hover click" ></a>
The popovers get initialized after every successful ajax call:
$(document).ajaxSuccess(function(){
var init = function() {
$('[data-toggle="popover"]').each(function(index) {
initPopover(this); //This is where the popover gets initialized
});
}
window.setTimeout(init,100); // set timeout to prevent function from being executed before content is replaced
});
The problem after a ajax call is, if a popup was visible, it stays visible even after the parent element has been removed. This is not an uncommon issue with popovers or dialogs according to google results, but the solutions I've come across so far did not seem very clean to me.
Two solutions, just to name some:
Hide every popover once an ajax finishes with success. This is not an option, because the content of my popovers is loaded dynamically via ajax once they get opened.
Have an array store all trigger elements. Once a Ajax success event occurs, loop through that array and check if that element is still there.
//Pseudocode
var popoverTriggers = [];
$('[data-toggle="popover"]').each(function(index) {
popoverTriggers.push(this);
}
Doesn't seem very clean to me either.
Does anyone know of a better way to do this?
I added a
$('.popover').remove();
To the event that should trigger the removal of the popover. This worked great for me.

Obscured div within script how to assign click on hover

I have a script which is obscured (ie cannot read the div elements from script). Upon rendering in inspect DOM element I can locate what the div I want to assign a function to. However I cannot do this. Do I need the div id within the script (ie obscured div id)?
I want to assign click on function and plan do it as follows:
<script>
$(document).ready(function () {
$('.contentoverlay').on('mouseover', function() {
click();
});
});
</script>
The script in itself is very long so I won't paste it here.
Overall I want to know:
Do I need to locate the obscure script's div is and assign my click function to it
Is the function above correct
If there are multiple overlays do I have to assign the function above to each one (the overlays in themselves are mouse pointer none, so they do pass down clicks, but would the function above get passed down or even blocked if I don't assign it to all the overlays)?
example: http://output.jsbin.com/joxetuc
First, i want explain my comment first, then i will answer your 3 questions in the end
A) honestly i have bad english here, i dont know what "obscured" means (even i google this), but i think that's means new DOM that newly created (dynamic created element) by javascript. like this:
started DOM <table></table>
New DOM <tr><td>texttt</td></tr>
the result <table><tr><td>texttt</td></tr></table>
if this not correct, my whole answer below will be wrong.
B) So, in jsbin example, i only give you div#container. And then create new DOM inside div#container when you click created button.
C) i create 1 function to handle if new DOM is clicked, which will write $(element).text() to div.log
//function to execute if element clicked
$('.container').on('click', '#newid', function(i,e){
var txt = $(this).text();
$('.log').append(txt+' ');
});
D) i handling event mouseover too with same function in click function. Because i'm lazy, i only write $(this).click(); which $(this) is refer to div#newid
//if mouseover, perform click
$('.container').on('mouseover', '#newid', function(i,e){
$(this).click();
});
so, in that jsbin i show you how to handle mouseover new DOM to execute click() function.
Now, Your Question
1) Do I need to locate the obscure script's div is and assign my click function to it?
You dont need it, as long as you know how to locate that element.
2) Is the function above correct?
that's not correct function. the correct 1 is:
parentElemenentOfNewDOM.on('mouseover', newDOMElement, function() {
$(this).click(); //this will perform your default click function that you give before
});
3) If there are multiple overlays do I have to assign the function above to each one (the overlays in themselves are mouse pointer none, so they do pass down clicks, but would the function above get passed down or even blocked if I don't assign it to all the overlays)?
you dont need to assign same function to handle multiple element (overlays). What you need is the correct script to handle all of your new multiple element. And my script will handle all of the new element.
if you want to know the different, see this DEMO http://output.jsbin.com/vukudu

How to bind an event within dynamically loaded content on a click event?

I have a div inside my html with the id pageContent. When users click various buttons, it will load the appropriate content. When a user clicks the javaQuestions button it loads, javaQuestions.html into the div just fine. However, inside, the javaQuestions.html, I have a collapsible list, and I can't figure out a way to "bind" the li collapse/uncollapse without having the user to click TWICE. Right now what I have is:
$("#pageContent").on('click', 'li', function (){
$('.collapsible').collapsible();
});
So I guess what happens is, first the user clicks on the button, and it loads content. Then, the user clicks on any li, and it enables the "collapsible()" function, but does not uncollapse/collapse the content. Only when the user clicks a second time does it works fine. I tried adding the line $('.collapsible').collapsible(); into the event that loads the javaQuestions.html content, but it doesn't do anything. Kind of at a roadblock, any ideas?
EDIT: Here is the code that loads the content:
$("#pageContent").on('click', '#javaQuestions', function (e) {
fadeIn("#pageContent", "../java-questions/javaQuestions.html", 50);
fadeIn("#commentsContent", "../comments/comment-section.html", 500);
});
I also really want to know how this will function once I figure it out. But as you can see, the above function loads the javaquestions.html, and I can't seem to find a way to ALSO bind 'li' to be collapsible in one swoop.
Have you tried using jQuery bind method? You can bind your handler to, say, body and then you don't have to care about loading and attaching a handler after it.
Update: may be this will help:
$(document).ready(function() {
$("body").on('click', '#pageContent li', function (){
$('.collapsible').collapsible();
});
});
Use this DOCUMENT because it is dynamically loaded
$(document).on("click","li #pageContent",function(){
$('.collapsible').collapsible();
});

Apply JS to dynamically created divs?

I have multiple div's on my page, that can be added to the page dynamically, and can also be removed.
On page load, the dynamically created div's are loaded from localStorage with uniqiue id's and a common class depending on the div, and I call a function along with that, content().
The function content() looks like this:
function content(){
alert("test");
$(".two button").click(function(){
var id = $(this).parent().attr("id");
alert(id);
});
}
Pretty simple, all it does is alert "test" when the function is called, and if you click .two <button>, it will alert .two <textarea> .val().
This works fine once the div's have been loaded, but I run into the problem when I clone the div's
When I clone the div's, it gives them a unique id and a common class like above. At the end of cloneDiv(), I call content(), so that clicking on the elements inside will produce the same results as above.
The problem is, the function will get called as many times as there are div's on the screen, but also means that clicking on the <button> in div .two will alert .two <textarea> .val() three times.
TLDR; Clicking on the button in .two get's called as many times as there are div's on the screen, as the function is called once the dynamic div is created, but should only be called once.
There's a lot of code to do all this, but I think I explained what happens pretty clearly. I will however whip up a demo if that would help more.
You want to use the .on function:
$('body').on('click', '.two button', function(){
var id = $(this).parent().attr("id");
alert(id);
});
I would change the 'body' part of that to the real container of these buttons. So say the buttons are always inside a content div with id my-div, you'd do:
$('#my-div').on('click', '.two button', function(){
var id = $(this).parent().attr("id");
alert(id);
});
You also only need this code to run once, so no need to put it in a function that gets called multiple times. Just put it in your $(document).ready(....).
A fiddle: http://jsfiddle.net/gromer/dxbqz/
This is what "event delegation" is for. You set up a handler on the document and it will handle events from its descendants, even if they are created after the handler is attached:
$(document).on("click", ".two button", function(){
// put a click hander on the document to process clicks
// from buttons that are descendants of elements with class=two
The problem is this: "At the end of cloneDiv(), I call content(), so that clicking on the elements inside will produce the same results as above." What happens is that you are compounding the events on to the existing elements so that is why you get so many callbacks. You should instead use the .on function, and use it only once. If you call .on multiple times it will produce the same results because multiple events will be registered.
$(".two button").on("click",function(){
var id = $(this).parent().attr("id");
alert(id);
});
Do this once, every button matching (".two button") will respond to it, even if appended later.
Another approach would be to pass in the element to the content() call and then mark it up from there if you are always calling this function when creating the elements anyway.
function content(element){
$(element).click(function(){
var id = $(this).parent().attr("id");
alert(id);
});
}
As a side note, using alerts to debug can be problematic as they interrupt program execution. I would highly recommend using console.log(id) instead and then looking in the console for your testing variables. console.trace() is also a good one to keep in mind if you are using a third party script and need to see what went wrong where.

Categories