let say I have a parent element which has so many nested child elements inside of itself:
<div id="p">
<div id="c1">
<div id="c2"></div>
<div id="c3"></div>
</div id="c4">
<div id="c5"></div>
</div>
</div>
I've already bind a click event on the parent:
$('#p').bind('click', function() {
alert($(this).attr('id'));
});
Because the event is assigned to the parent element, I always see the parent id, however, I'm wondering if there is any possible way to find out which of this child elements has been clicked?
I also can't assign any event to the child elements or remove the event listener from parent div.
You need to pass event object to function to get the item that triggered the event, event.target will give you the source element.
Live Demo
$('#p').bind('click', function(event) {
alert(event.target.id);
});
or
Live Demo
$('#p').bind('click', function(event) {
alert($(event.target).attr('id'));
});
Edit
The first method event.target.id is preferred over second $(event.target).attr('id') for performance, simplicity and readability.
You can try the below code. Also try the jsfiddle too(demo).
$('#p').on('click', function(event) {
alert(event.target.id);
});
Try the demo
The answer to your second question is you can assign event to the child and remove from it's parent. Check this out.
.stopPropagation();
Prevents the event from bubbling up the DOM tree, preventing any
parent handlers from being notified of the event. Read more
if you want the specific event to be executed only and allow no other event to be fired you use code below
event.stopImmediatePropagation()
Keeps the rest of the handlers from being executed and prevents the event from bubbling up the DOM tree. Read more
I hope this will solve your problem. If you have any questions please don't hesitate to ask. Thanks
If your elements have grandchildren, there is a better way to get just the child. Note the greater than sign.
$('.parent > .child').click(function() {
// This will be the child even if grandchild is clicked
console.log($(this));
});
Related
As the title reads, is there a way to update the variable (which links to how many divs there is in a parent)?
The code I have works, but I was looking for another way...
The code I have:
function addDiv() {
//adds a div into the parent
}
parent.addEventListener("mouseover", ()=>{
getAllLists = parent.querySelectorAll(".list-name-tile")
getAllLists.forEach(list => {
list.addEventListener("click", ()=>{
//other code
})
});
})
In my code, I used "mouseover" to update getAllLists; I was just wondering if there was another way to do this and achieve a similar effect or is this the way to it best? Please ask me to clarify or if you need additional information.
Thank you!
Retrieving the div elements in the mouseover event listener is ok in my opinion.
However, there is a problem in your code. Each time you hover over the parent element, the click eventlistener is attached to the child elemens over and over again. You can try this by inserting a console.log() in the click event handler. Hover over the parent element a few times and then click on a child element. You will see the output of the console.log a few times.
This is because the clicker event listener is attached everytime you hover over the parent element.
Possible solution
As far I understand your question you would like to add a click eventlistener to all child element (even the ones which are added dynamically). If thats the case you can make usage of Event Delegation.
Bubbling also allows us to take advantage of event delegation — this concept relies on the fact that if you want some code to run when you select any one of a large number of child elements, you can set the event listener on their parent and have events that happen on them bubble up to their parent rather than having to set the event listener on every child individually. Remember, bubbling involves checking the element the event is fired on for an event handler first, then moving up to the element's parent, etc.
A good example is a series of list items — if you want each one to pop up a message when selected, you can set the click event listener on the parent , and events will bubble from the list items to the .
Event bubbling and capture (scroll down to the section "Event delegation")
Via Event Delegation you can do it this way:
HTML
<div id="parent">
<div class="list-name-tile">First div</div>
<div class="list-name-tile">Second div</div>
</div>
JavaScript
const parent = document.getElementById("parent");
parent.addEventListener("click", e => {
if (e.target.classList.contains("list-name-tile")) {
// Do stuff
}
});
function addDiv() {
const div = document.createElement("div");
div.classList.add("list-name-tile");
div.textContent = "Next div";
parent.appendChild(div);
}
addDiv();
In the example I have attached a click event listener to the parent element. So whenever you click on a child element the event is "bubbling" to the next ancestor which is your parent element. There we have the event listener and can handle it. In the example I have filtered it to only do something when the element, which has triggered the event, has a specific class. You can also filter for specific events and so on.
I have a Div with a link remove when I click on the remove this Div removed.
JS FIDDLE
<div class="bar">
<p style="float:left"> Hello world</p>
remove
</div>
Here the div with Class .bar will remove when I click on the link remove which is working fine.
But I also created a link below the div(.bar) which is :
+ Add New
On clicking +Add New will create a new .bar div.
$('.add').click(function() {
$(".holder").prepend('<div class="bar"><p style="float:left"> Hello world</p> remove </div>');
});
But the Problem is when this new .bar div is created clicking on the remove not working. This new .bar div not remove.
why is that ? is there any other way to do this ? Any help will be much appreciated.
You need to use Event Delegation. You have to use .on() using delegated-events approach.
i.e.
$(document).on('event','selector',callback_function)
Example
$('.holder').on('click', '.delete', function() {
$(this).parent('.bar').remove();
});
In place of document you should use closest static container.
DEMO
The delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time. By picking an element that is guaranteed to be present at the time the delegated event handler is attached, we can use delegated events to bind the click event to dynamically created elements and also to avoid the need to frequently attach and remove event handlers.
You should use event delegation:
$('.holder').on('click', '.delete', function() {
$(this).parent('.bar').remove();
});
Here .holder is the closest static parent element.
DEMO: http://jsfiddle.net/jnLfh/5/
You need event delegation for dynamically added elements which are not present in DOM at the time of execution of event binding code. You can delegate event to static parent of dynamic element, in the given example you can delegate it to .holder or document
Live Demo
$(".holder").on('click', '.delete', function() {
$(this).parent('.bar').remove();
});
Delegated events
Delegated events have the advantage that they can process events from
descendant elements that are added to the document at a later time. By
picking an element that is guaranteed to be present at the time the
delegated event handler is attached, you can use delegated events to
avoid the need to frequently attach and remove event handlers, jQuery Doc
Change to this:
$(document).on('click', '.delete', function(e) {
e.preventDefault(); // stops the jump
also a note, if you want to delegate the event then you should always try to delegate to the closest static parent (Which was available at the time of doc ready), so here in your case is <div class='holder'> then you can change to this:
$('.holder').on('click', '.delete', function(e) {
e.preventDefault(); // stops the jump
but here one more thing for note if you are delegating to the closest static parent then you have to put this click event in your "document ready block".
The selector will not recognize the new div added by the script. For this you need to add event delegation. Here's an example
using "on"
$('.delete').on('click', function(){
$(this).parent('.bar').remove();
});
using "live" (might be depreciated now. Please check)
$('.delete').live('click', function(){
$(this).parent('.bar').remove();
});
I have an element within another element and both have separate click functions. What I would like to do is ignore or stop the parent element if the child element has a click function. For example:
<div class="parent">
<div class="child1">Child Click Function</div>
Parent Click Function
</div>
<script type="text/javascript">
document.observe('dom:loaded',function(){
if ($$('.parent') != undefined) {
$$('.parent').invoke('observe','click', function(e) {
alert('parent');
});
}
if ($$('.child1') != undefined) {
$$('.child1').invoke('observe','click', function(e) {
alert('child');
});
}
});
</script>
What happens is that when child1 is clicked, both that and parent are triggered since child1 is within parent. I would like disable/stop the observe when child is selected, but when you click on anything else inside parent, it works as it should.
Thanks.
You're encountering what's known as "event bubbling". Events on a given element bubble up the DOM until they reach the root node unless you explicitly stop the bubbling. Since it looks like you're using Prototype, updating your child's event handler to the following should do the trick:
$$('.child1').invoke('observe','click', function(e) {
Event.stop(e);
alert('child');
});
http://api.prototypejs.org/dom/Event/prototype/stop/
I'm not sure which one works, but I usually use both:
if (event.cancelBubble)
event.cancelBubble();
if (event.stopImmediatePropagation)
event.stopImmediatePropagation();
And pass the click event into the onclick function.
Both stop propagation and cancel bubble will stop the propagation of the event all together ,
from what I get is you want to bypass the event associated with the parent.
I would suggest to use .unbind() on the parent in case the child is clicked. For example,
(CHECK CHILD CLICK) {
$('.parent').unbind('click');}
Is there an efficient way in jQuery to detect if anything other than a specific element (and it's children) has been clicked ??
<body>
<header></header>
<p>stuff<p>
<div class="floating-form">
<form>more stuff</form>
</div>
<footer></footer>
</body>
Whats the best way to remove the floating form, by listening for a click on anything other than the floating form?
Bind a click event listener to $(document) that removes div.floating-form.
Bind a click event to div.floating-form that stops event propogation.
The usual approach is to assign a click event handler to the specific element that does nothing other than stop event propagation. Then assign another click handler to the entire page (i.e. to the document) that removes the element in question. Clicks on the element won't propagate up to the document, so you'll get the functionality you want.
You can use the event.target attribute to determine what element triggered the click.
http://api.jquery.com/event.target/
$(document).click(function() {
//do something
});
$(".floating-form").click(function() {
return false;
});
<div id="menu">
<div class="menuitem-on" id="home">Home</div>
<div class="menuitem-off" id="mycart">My Cart</div>
<div class="menuitem-off" id="shop">Shop</div>
</div>
how do I assign click handlers to each of the children of menu with jquery?
$("#menu").delegate('div','click', function(){
//do your thing here
});
Handler is on parent, so only one. You can add more div without changing code.
Here is a fiddle page to show a couple of different selector options to get the click anywhere, or just the first level. Shows the use of the event target, currentTarget as well: http://jsfiddle.net/8GLZJ/
Update 3/18/2013 for 1.9.1+ jQuery use:
$("#menu").on('click','div', function(){
//do your thing here
});
You don't want to do that because:
You create a event handler for each children
If you dynamically add more elements, the handler won't work for them.
A better solution is to add a single event handler to the parent element and then do a different action based on the event.target property, that contains the clicked element.
This happens because of event bubbling and it's a cool feature you should take advantage of.
jQuery in particular abstracts this under what they call live events so you should go with those.
$("#menu div").click(function(){
// your code goes here
// $(this) give you the element that was clicked
});
Binding event to each one of element using click() or bind('click', ...) isn't a good solution, because in case if you have, lets say 50 items, you will have to bind 50 same handlers - browser has to register them all.
Better solution is to use feature called event delegation - and jQuery has special method for that - delegate(). So your code will look like this:
$('#menu').delegate('div', 'click', function() {
//code of your handler - 'this' refers to clicked element
});
There is an article with video showing difference between click, live and delegate in jQuery: NetTuts+.
Something like
$("#menu div").on('click', function(){
//alert('clicked');
});