I have a problem with conflicting parent/child jquery functions. The child function is a bootstrap function, the parent is a custom function. The idea is that the parent div (see code below) can contain too much data, and thus should be limited in height. there is a toggle when you click in the div, to expand it, but that should not happen when i click on a child element, because this one also collapses down.
<div id="items" class="semiCollapsed">
<span data-toggle="collapse" data-target="#x" > an item</span>
<div id="x" class="collapse">description of item</div>
... more items ...
</div>
The function for my parrent JQuery is:
jQuery(document).ready(function() {
jQuery('#items').click(function(event) {
event.preventDefault();
$("#items").toggleClass("semiCollapsed");
})
});
and the css:
.semiCollapsed {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-height:110px;
}
Bootstrap Collapse:
http://pastebin.com/Xfnq7R4i
The problem I'm having is that the parent get called when i call the child function. How to fix this?
JSFiddle:
http://jsfiddle.net/7fdjL3qx/
If clicked item is not target we must return. if (event.target !== this) return;
jQuery('#items').on('click', function (event) {
if (event.target !== this) return;
event.preventDefault();
$(this).toggleClass("semiCollapsed");
});
Fiddle: http://jsfiddle.net/abhiklpm/7fdjL3qx/1/
use event.stopPropagation(); instead of event.preventDefault();.
Because events happening on child bubbles up to the parents so all the events bound on parents also gets executed.
So to stop the event to bubble up to the parent you need to have event.stopPropagation() on child click events.
You can use check event.target.id inside click element and if it is items then only toggle class.
jQuery(document).ready(function() {
jQuery('#items').click(function(event) {
event.preventDefault();
if(event.target.id=="items")
{
//use this for clicked element instead of finding it again using id
$(this).toggleClass("semiCollapsed");
}
});
});
Related
I am trying to create an accordion inside of an accordion... and I am struggling a little.
essentially, I have a div .applicant, which upon click adds a class .expand, which sets the height to auto, but, inside of the .applicant div, I have another div .applicant-child, which SHOULD do the same thing, and does... but, .applicant closes when you click .applicant-child, meaning you have to click the .applicant again to open view the nested element.
Here is my code:
HTML
<div class="row">
<div class="col-sm-12">
<div class="applicant">
<p><b>PS4 Tournaments</b></p>
<div class="applicant-child">
<p>lalal</p>
<p>lalal</p>
</div>
</div>
</div>
</div>
jQuery
$('.applicant').click(function(){
if ($(this).hasClass('expand')) {
$(this).removeClass('expand');
} else {
$( this ).addClass('expand');
}
});
$('.applicant-child').click(function(){
if ($(this).hasClass('expand')) {
$(this).removeClass('expand');
} else {
$( this ).addClass('expand');
}
});
I could simply remove $(this).removeClass('expand'); from .appliant, but we'll be displaying a lot of data, so that isn't ideal.
How do I solve this?
Thanks in advance :)
That's just event bubbling an expected behaviour.
See this link on jQuery on how to disable the click-Event to bubble up the DOM and triggering the event on your parent element.
Basically, you just have to do this:
$('.applicant-child').click(function(event){
event.stopPropagation();
if ($(this).hasClass('expand')) {
$(this).removeClass('expand');
} else {
$( this ).addClass('expand');
}
});
You want to prevent bubbling. Bubbling means, that the event you are reacting to is being passed up the DOM to the parent objects, until it reaches the window.
Check out the "event.stopPropagation()" method, which will prevent any subsequent listeners from reacting.
On your click handler if you pass through a param:
$('.applicant').click(function(event){
console.log(event.target);
if ($(this).hasClass('expand')) {
$(this).removeClass('expand');
} else {
$( this ).addClass('expand');
}
});
you can use event.target to check if you are clicking on the parent or the child and decide on what action to take from there.
My Jquery one() function dies after second click instead of first click. Here is my HTML
<div class="box">
<div class="call" data-tai="5">CLICK</div>
</div>
and heres my Jquery
$('body div').one('click', '.call', function() {
var mother = $(this).parent();
if(mother.css('position') === 'static')
mother.css('position', 'relative');
var tai = $(this).data('tai');
$.ajax({
method: 'GET',
url: '/bootstrap/call.php',
data: 'tai='+tai,
dataType: 'html',
success: function(ret) {
mother.append(ret);
},
});
return false;
});
Interesting thing is, if i don't use return false;, it dies after first click. However bubbling occurs and it appends 2 html tags instead of 1, inside box element. Thanks for help
$('body div')
would select both the divs and attach click handlers to both of them. When you click on the nested div then, both clicks will be fired. Use a specific selector to avoid this.
$('.call')
could perhaps achieve this.
That's because event handlers bound by using .one will be fired once for each element in the jQuery collection. Since the return false stops the propagation of the event, if you click on the .call element, click handler of the parent element is not executed but the parent element still has an active click handler. You should use a more specific selector for selecting the target element. If the click handler should be bound to the div.call elements:
$('.box div.call').one(...);
Now, if .box elements have 9 div.call descendants then you have 9 click handlers! After clicking on each element jQuery unbinds the handler for that specific element.
It's not once for all elements, it's once for each element.
If the handler should be called once for all the matching elements you can use the delegation version of the .one method:
$(document).one('click', '.box div.call', function() {
// ...
});
And if you want to delegate the event and have the handler working once for dynamically generated elements you can use the .on method and :not selector:
$(document).on('click', '.box .call:not(.clicked)', function() {
$(this).addClass('clicked');
// ...
});
Now the handler is called once for each .call element. Since :not excludes the elements that have .clicked class the selector doesn't match the already-clicked elements.
Events bubble in JavaScript. Your code
$('body div').one('click', '.call', function() {
}
wires up on both
<div class="box"> <!-- This -->
<div class="call" data-tai="5">CLICK</div> <!-- And this -->
</div>
You need a more specific selector. If this div is a parent element in the body like this:
<body>
<div class="box">
<div class="call" data-tai="5">CLICK</div>
</div>
<div class="box">
<div class="call" data-tai="5">CLICK</div>
</div>
</body>
then you can use a selector like this:
$('body > div').one('click', '.call', function() {
}
The question is - where do you expect your click event to be placed? Perhaps the div with the box class?
$('div.box').one('click', '.call', function() {
}
This assumes that the .call divs are being added dynamically to the .box div.
P.S. - if you want to stop the bubbling, I suggest you pass in the event object to your click event and call stopPropagation()
$('div.box').one('click', '.call', function(evt) {
evt.stopPropagation(); // no bubbling
}
I've got the following html
<div id="parent">
<div id="window"><!-- contents of window ---></div>
</div>
Parent is 100% width with padding top and bottom and Window is centered inside it with a width of 600px.
What I need to figure out is a jquery selector which will trigger when the user clicks anywhere that is inside of Parent but outside of Window
Check if the target has id parent
$('#parent').on('click', function (e) {
if (e.target.id == "parent") {
//code for clicking outside window but inside parent
}
});
DEMO
You can bind a click handler to #parent and then prevent propagation of clicks from #window. This allows you to have additional nested content inside of #parent without messing around with lists of the event targets.
$("#window").on("click", function(e) {
e.stopPropagation();
});
$("#parent").on("click", function(e) {
// Do your thing
});
See a demo here: http://jsfiddle.net/4kGJX/
you can try this way
$('#parent').not("#window").on('click', function (e) {
//do stuff
});
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));
}
}
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.