Basicllay i have a div with a class called .li-level-1, and inside that i have differnt ul's with lists. i Have it set up so when you click on a li-level-1 div displays the ul's and li's inside that div by animating a drop down and when you click on the next one it closes the one previously opened and slidesDown the next one.
the only thing is the a links that are inside the div's seem to trigger the slideUp/Down on level-1 and animation as well.
any Suggestions?
$('.sitemap_page .li-level-1').each(function(){
$(this).find('ul.ul-level-2').hide();
$(this).click(function(){
var this_list = $(this);
this_list.parent().find('.open').each(function(){
$(this).slideUp(function(){
this_list.find('ul.ul-level-2').addClass("open").slideDown();
}).removeClass('open');
});
if(this_list.find('ul.ul-level-2.open').length == 0) {
this_list.find('ul.ul-level-2').addClass("open").slideDown();
}
});
});
That's because of event bubbling: the click event raised on the <a> elements bubble up to their containing <div> and cause your event handler to execute.
One way to work around that problem would be to use event.target to determine the event's origin, and only perform the sliding animations if the event did not originate on a link:
$(this).click(function(event) {
if (!$(event.target).is("a")) {
var this_list = $(this);
this_list.parent().find('.open').each(function() {
$(this).slideUp(function() {
this_list.find('ul.ul-level-2').addClass("open").slideDown();
}).removeClass('open');
});
if (this_list.find('ul.ul-level-2.open').length == 0) {
this_list.find('ul.ul-level-2').addClass("open").slideDown();
}
}
});
The problem is with event bubbling as sugested by Frederic. The other possible solution is to divide your div into title and content divs. Hold data in content and check click on title (not on the parent list). This means rebuilding the handler but the code will be clearer and it won't depend on event.target.
Related
I'm trying to get link (url of clickable elements) with the left mouse click, next method doesn't work for all elements:
function callback(e) {
if (e.button != 0 ) {
return;
}
alert(e.target.href);
}
document.addEventListener('click', callback, true);
For example for some elements on Youtube site - titles or thumbnails (all of them are clickable and they lead to some video/playlist):
href is undefined
but it's clickable and Google Chrome browser shows a preview of link to which this element leads:
UPDATE
The problem that some A tags on Youtube site wraps other elements inside them: <span>...<span/><div.......>
I tried debug mode (inspect), selected some of such element to inspect and it picked <span> inside of <a>.
Additional Solution: https://jsfiddle.net/z2huqjjh/2/ (will be good solution if links (A tags) are dynamically being added to a page)
By default, events bubble. This means that you could have an element that is nested within 100 others. Clicking on that nested element will cause a click event and that event will propagate up through all the ancestor elements until it is either cancelled or reaches the window.
Now, just about everything in the document is clickable. Just because something is clickable doesn't mean it will navigate to a URL, like an <a> element does.
For example:
document.querySelector("div").addEventListener("click", function(){
alert("Thanks for clicking me!");
});
<div>I'm a <div> and I don't have an 'href'. But, click me anyway</div>
Since only a few elements actually have an href attribute, you could alter your code to look only at those:
function callback(e) {
if (e.button != 0 ) {
return;
}
alert(e.currentTarget.href);
}
// Get all the anchors and place into an array
var anchorArray = Array.from(document.querySelectorAll("a"));
// Loop through the anchors
anchorArray.forEach(function(anchor){
// Assign a click event handler to each. When the click event
// bubbles to the element, the callback will be called
anchor.addEventListener('click', callback);
});
<div>I'm a div - click me anyway</div>
<span>I'm a span inside of an anchor, click me too!</span>
So I have a parent div with different elements inside. Right now I have it set up so when that parent div is clicked, it applies a "selected" css attribute (just highlights it). However, there is an anchor tag inside this div and I don't want the div to highlight if the anchor is clicked.
My code to highlight the div
$(document).on("click",".playlist-row",function() {
var selected = $(this);
highlight(selected);
});
Ideally, I want it to behave like this: (just pseudo code)
$(document).on("click",".playlist-row",function() {
var selected = $(this);
if ($(".childElement) is not the part clicked) {
selectSongInPlaylist(selected);
}
});
Any elegant ways to get something like this to work?
You could use stopPropogation() as in http://api.jquery.com/event.stopPropagation/ on the child elements like $('.childElement').click(function(e){
e.stopPropagation();
}); to prevent the click event propagating to the parent element. You could also check the event.target property as described here http://api.jquery.com/event.target/
you need to prevent the click event bubbling up to the container
capture the event and use event.stopPropagation
$(document).on('click', "a", function(event){
event.stopPropagation();
});
I will assume that I understood your question, so here's what I would probably do:
$(document).on("click", ".playlist-row", function(e) {
if (!$(e.currentTarget).is("a")) {
selectSongInPlaylist($(this));
}
}
Good morning,
I have a set of boxes on a page that are presented as a list, and within these boxes there might be some links that can be clicked. I want the links within the boxes to work as normal (i.e. bubble up and either perform the default action or then be handled by event handlers further up the DOM), but if the box is clicked anywhere else then it should be caught by a particular event handler attached to the "list" containing all the boxes.
Simple html representation
<div class="boxlist">
<div class="box" data-boxid="1">
Some text, and possibly a link and another link, and perhaps even a third link.
</div>
<div class="box" data-boxid="2">
Some more text, this time without a link.
</div>
</div>
The javascript that I thought should work.
$(function () {
$('.boxlist').on('click', '.box :not(a)', function (e) {
var boxid= $(this).closest('.box').data('boxid');
console.log('open: ' + boxid);
});
});
My expectation was that the above javascript should handle all clicks that did not originate from tags. However, for some reason when the box is clicked (either the box itself, or an tag, doesn't matter), it fires this event X times, where X is the total number of tags within the list of boxes.
So I have two questions:
1. What am I doing wrong with the :not() selector.
2. Is there a better way to handle this scenario?
Thank you for helping!
linkUsing jQuery :not selector actually is very slow ex:http://jsperf.com/not-vs-notdasdsad/4 and it's way better to just use event delegation. So in this case you want to keep track of every click on the .boxlist but check the node type to see if its an anchor or not. This is an example.
$(function () {
$('.boxlist').on('click', function(ev){
if(ev.target.tagName != "A"){
// handle box click code
console.log('box click');
return false;
}
// Otherwise allow event to bubble through.
});
});
and here is a jsfiddle example
http://jsfiddle.net/drXmA/
Also their are a few reasons your code doesn't work
.box :not(a)
should be
.box:not(a)
and the reason this also does not work is because .box is not an anchor tag it has children elements that are anchor tags it will never find an anchor tag named .box if their is one the callback would not execute. Changing the .box to an anchor tag will make it so the code doesn't execute because .box is an anchor and it is only running when .box:not(a)
I guess you want something like this:
$('.boxlist').on('click', '.box:not(a)', function (e) {
var boxid = $(this).closest('.box').data('boxid');
console.log('open: ' + boxid);
}).on('click', '.box a', function (e) {
e.preventDefault().stopPropagation();
});
DEMO FIDDLE
I think better to stop the default behavior and stop the event bubbling to its parent. .on() chain to the .box items excluding <a> from it and stop the default behavior and event bubble with e.preventDefault().stopPropagation();
How can I trigger a function when I click anywhere on my page except on one div (id=menu_content) ?
You can apply click on body of document and cancel click processing if the click event is generated by div with id menu_content, This will bind event to single element and saving binding of click with every element except menu_content
$('body').click(function(evt){
if(evt.target.id == "menu_content")
return;
//For descendants of menu_content being clicked, remove this check if you do not want to put constraint on descendants.
if($(evt.target).closest('#menu_content').length)
return;
//Do processing of click event here for every element except with id menu_content
});
See the documentation for jQuery Event Target. Using the target property of the event object, you can detect where the click originated within the #menu_content element and, if so, terminate the click handler early. You will have to use .closest() to handle cases where the click originated in a descendant of #menu_content.
$(document).click(function(e){
// Check if click was triggered on or within #menu_content
if( $(e.target).closest("#menu_content").length > 0 ) {
return false;
}
// Otherwise
// trigger your click function
});
try this
$('html').click(function() {
//your stuf
});
$('#menucontainer').click(function(event){
event.stopPropagation();
});
you can also use the outside events
I know that this question has been answered, And all the answers are nice.
But I wanted to add my two cents to this question for people who have similar (but not exactly the same) problem.
In a more general way, we can do something like this:
$('body').click(function(evt){
if(!$(evt.target).is('#menu_content')) {
//event handling code
}
});
This way we can handle not only events fired by anything except element with id menu_content but also events that are fired by anything except any element that we can select using CSS selectors.
For instance in the following code snippet I am getting events fired by any element except all <li> elements which are descendants of div element with id myNavbar.
$('body').click(function(evt){
if(!$(evt.target).is('div#myNavbar li')) {
//event handling code
}
});
here is what i did. wanted to make sure i could click any of the children in my datepicker without closing it.
$('html').click(function(e){
if (e.target.id == 'menu_content' || $(e.target).parents('#menu_content').length > 0) {
// clicked menu content or children
} else {
// didnt click menu content
}
});
my actual code:
$('html').click(function(e){
if (e.target.id != 'datepicker'
&& $(e.target).parents('#datepicker').length == 0
&& !$(e.target).hasClass('datepicker')
) {
$('#datepicker').remove();
}
});
You could try this:
$(":not(#menu_content)").on("click", function(e) {
e.stopPropagation();
// Run your function when clicked anywhere except #menu_content
// Use with caution, 'cause it will prevent clicking on other elements
});
$("#menu_content").on("click", function(e) {
e.stopPropagation();
// Run when clicked on #menu_content
});
I have a JavaScript that displays a DIV (sets its display css property from 'none' to 'normal'. Is there a way to give it focus as well so that when I click somewhere else on the page, the DIV loses focus and its display property is set to none (basically hiding it). I'm using JavaScript and jQuery
For the hide the div when clicking any where on page except the selecteddiv
$(document).not("#selecteddiv").click(function() {
$('#selecteddiv').hide();
});
if you want to hide the div with lost focus or blur with animation then also
$("#selecteddiv").focusout(function() {
$('#selecteddiv').hide();
});
with animation
$("#selecteddiv").focusout(function() {
$('#selecteddiv').animate({
display:"none"
});
});
May this will help you
The examples already given unfortunately do not work if you have an iframe on your site and then click inside the iframe. Attaching the event to the document will only attach it to same document that your element is in.
You could also attach it to any iframes you're using, but most browsers won't let you do this if the iframe has loaded content from another domain.
The best way to do this is to copy what's done in the jQuery UI menubar plugin.
Basic example HTML:
<div id="menu">Click here to show the menu
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
And the jQuery needed to make it work:
var timeKeeper;
$('#menu').click(function()
{
$('#menu ul').show();
});
$('#menu ul').click(function()
{
clearTimeout(timeKeeper);
});
$('#menu').focusout(function()
{
timeKeeper = setTimeout(function() {$('#menu ul').hide()}, 150);
});
$('#menu').attr('tabIndex', -1);
$('#menu ul').hide();
What it does is give the menu a tab index, so that it can be considered to have focus. Now that you've done that you can use the focusout event handler on the menu. This will fire whenever it has been considered to lose focus. Unfortunately, clicking some child elements will trigger the focusout event (example clicking links) so we need to disable hiding the menu if any child elements have been clicked.
Because the focusout event gets called before the click event of any children, the way to achieve this is by setting a small timeout before hiding the element, and then a click on any child elements should clear this timeout, meaning the menu doesn't get hidden.
Here is my working jsfiddle example
$(document).mouseup(function (e)
{
var container = $("YOUR CONTAINER SELECTOR");
if (!container.is(e.target)&& container.has(e.target).length === 0)
{
container.hide();
}
});
You can bind a function on click of body and check if its the current div using e.target (e is the event)
$(document).ready(function () {
$("body").click(function(e) {
if($(e.target).attr('id') === "div-id") {
$("#div-id").show();
}
else {
$("#div-id").hide();
}
});
});
Regarding mouse clicks, see the other answers.
However regarding lost focus, .focusout is not the event to attach to, but rather .focusin. Why? Consider the following popup:
<div class="popup">
<input type="text" name="t1">
<input type="text" name="t2">
</div>
What happens on moving from t1 to t2:
t1 sends focusout, which bubbles up to $('.popup').focusout
t2 sends focusin, which bubbles up to $('.popup').focusin
... so you get both types of event even though the focus stayed completely inside the popup.
The solution is to analogous to the magic trick done with .click:
$(document).ready(function() {
$('html').focusin(function() {
$('.popup').hide();
});
$('.popup').focusin(function(ev) {
ev.stopPropagation();
});
});
(side note: I found the .not(...) solution not working bc. of event bubbling).
Bonus: working fiddle click me - open the popup, then try tabbing through the inputs.
I was also looking for this and here I found the solution https://api.jquery.com/mouseleave/. This may be useful for future readers.
The mouseleave event differs from mouseout in the way it handles event bubbling. If mouseout were used in this example, then when the mouse pointer moved out of the Inner element, the handler would be triggered. This is usually undesirable behavior. The mouseleave event, on the other hand, only triggers its handler when the mouse leaves the element it is bound to, not a descendant.
On triggering mouseup() event, we can check the click is inside the div or a descendant and take action accordingly.
$(document).mouseup(function (e) {
var divContent= $(".className");
if(!divContent.is(e.target) && divContent.has(e.target).length === 0) {
$(".className").hide();
}
});
I personally haven't tried blur on divs, only on inputs etc. If blur eventhandler works, it's perfect and use it. If it doesn't, you could check this out:
jQuery animate when <div> loses focus
$('.menu > li').click(function() {
$(this).children('ul').stop().slideDown('fast',function()
{
$(document).one('click',function()
{
$('.menu > li').children('ul').stop().slideUp('fast');
});
});
});
Showing is easy
$('somewhere').click(function {$('#foo').show();})
For hiding
How do I hide a div when it loses its focus?
With jQuery you can hide elements with hide(), ex: $("#foo").hide()
Hide element in event listener:
$("#foo").blur(function() {
$("#foo").hide();
});