When I access <div> or <p> elements by class with jQuery for a click function, it repeats the event by how many elements are in the array or stack. So, if I have 3 <div> elements on top of each other or next to each other, the one on the bottom, or the one to the right, will go through the event once and the one on the top or the left will go through the event 3 times.
Am I doing something wrong? Or is this not meant to be done with jQuery?
[revision]
sorry if i worded this in a confusing way. here is a link... you will better understand my problem there. just add a couple new elements via the form and click on them.
http://jsfiddle.net/rNj6e/
Now that you've posted a fiddle showing the problem, I can actually answer. The problem is that you bind the click event handler to .dp inside the click event handler bound to #add. So what happens is this:
You fill in the form and click #add, which creates a new element with class dp and appends it
It then binds a click event handler to every element with class dp (there's only 1, the 1 we just added)
You fill in the form again, click #add, which repeats steps 1 and 2, so it binds another click event listener to the first .dp element, and binds one to the new element.
Repeat as necessary, binding more and more event handlers to the existing elements every time you click #add!
To fix this, you need to bind the event handler to .dp outside of the #add event handler. The problem is that you're creating new .dp elements on the fly, so just using .click won't bind to elements that are not in the DOM yet. To solve that, you can use delegate, which binds an event handler to elements matching the selector now and in the future:
$("#preview").delegate(".dp", "click", function(event){
alert(this.id);
});
Here's an updated fiddle.
Try:
$(".some_class").click(function(event){
alert(event.target.id);
}).children().click(function(event) {
return false;
});
This should prevent the click event from bubbling through the children, this happens when you click on the children contained in the div.
You are recieving a blank ID because the target of your clicks is most likely the child you clicked and you haven't given it an ID.
To prove this try...
$(".some_class").click(function(event){
alert(event.target.nodeName);
});
which alerts you the nodeName (the name of the html tag) you just clicked.
Change it to this:
$(".some_class").each( function () {
jQuery(this).click(function(event){
alert(event.target.id);
});
});
Related
I have an element with properties such as drag and drop and 1 click event handler. I have cloned this element, and find that the cloned element has the event handler working, as long as the original element is still in the DOM. The moment I remove the original from the DOM, however, the event handler is destroyed. My code goes:
el = $(#id).clone(true)
$('#container').packery('addItems', el)
el.appendTo('#container')
$('#container').packery('layout')
$('#lowerContainer > ' + #id).remove()
The event handler on el works as long as the last line is not added. However, adding $('#lowerContainer > ' + #id).remove() kills the handler. Does anyone know how I can keep the handler in cloned element even after removing the original? Thanks in advance!
You should define your click handler on container rather than on individual items:
$('#container').on('click', '.item', function() {...});
In this case it will handle clicks as on existing items as on ones added later.
I have a table where i have bound all my elements with class="shift" to a click function.
Now, because I also need to use another click event on part of the element, I would like to unbind the click event on element when the mouse enters the element and rebind when i leaves (meant for some touch events and whatnot)
Now, I bind like this
$("table").on("touchstart mousedown",".shift", function(e){ ... })
But when i try to unbind on a specific element, say it has a class="selected" added to distinguish the current element i use:
$("table").off("touchstart mousedown",".shift.selected")
which does not work....
I can remove all the handlers at once, but it would be wasteful to remove all the handlers and reinsert them as soon as the mouse leaves.
So, is there a way to remove the handler on a single element after the event is bound to all current and future elements?
Thanks in advance!
You don't need to unbind the click event on the element when the mouse enters. I know, the element click event will trigger when you click an inner element with the click event bound, right ? you can stop that:
The click handler of the inner element must look like this:
$("some inner element").click(function(event) {
//That's what are you looking for ;)
event.stopPropagation();
//You code here
});
event.stopPropagation() will prevent the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.
Is there anything wrong that can happen if I bind a null selector using on? It would simplify my code and allow me to chain a few things if I didn't have to explicitly check if the selector is null myself.
Any performance, security, or memory-leak implications if I do this a dozen times on my page?
$(document.body).on('click', null, function () { ... }
If you plan on dynamically adding elements, there is nothing wrong by binding on a higher element using the .on() method.
Keep in mind though you have to specify a selector that will ultimately define the dynamically added elements.
The code below will fire when a label is clicked.
$(document).on('click', 'label', function(e) {
alert('dynamically added label clicked');
});
This code will fire when any element is clicked.
$(document).on('click', null, function (e) {
alert('fired regardless what element you clicked');
});
From the jQuery docs:
A selector string to filter the descendants of the selected elements
that will call the handler. If the selector is null or omitted, the
handler is always called when it reaches the selected element.
If your problem is that the elements that raise the click event are dynamically added you can still use a direct event handler on body and catch those events.
The delegated event handler gives you the opportunity to filter out some of those click events, but it seems that's not the case since you are setting the selector to null.
For example, if you have a div and add buttons inside and add an event handler to the click event on the div you'll catch all the click events from all the buttons, even the ones added dynamically.
<div>
<input type="button" value="add button" id="buttonAddMore"/>
<span id="whatClicked"></span>
</div>
$('div').on("click", function(event){
$('#whatClicked').text("the id of the clicked element inside the div is: " + event.target.id);
});
This fiddle demonstrates this.
The delegated events have other subtleties, such as, they won't respond to events raised in the elements they are registered in, in this example that would be a click on the div, and that might be important.
Either way if you look at how the events are registered, in your case you can have a look by calling in the console $._data(document.body, "events") and have a look at the click event handler with your method and registered using the shorthand version (i.e. .click or on("click", function() {...})) you'll see that they produce the same object, except for the selector being null (.on("click", null...) in one case and undefined in the other (.click)
NOTICE: The cause of the problem has been found, read the comments to the first answer.
I have a dropdown list of things, that is hidden until the user invokes it.
It's something like this:
<div>
<button></button>
<ul>
<li></li>
....
<li></li>
</ul>
</div>
The basic idea:
The list becomes visible when the user presses the button shown in the code above.
I need to make the list able to be navigated by keyboard,
i.e. if the user presses up or down while the list is open, the appropriate li will be selected (as if the mouse was hovering over it instead)
The event listener responsible for giving this functionality to the list should be attached when the list becomes visible and be removed when the list becomes hidden again.
Something like what Bitbucket does for the dropdown lists, but even simpler.
The issue:
I tried to attach an event listener to the ul and then on the div element, when the former had no effect, to no avail.
The code is this
ON SHOW
this.<ul or div element here>.addEventListener('keydown', this.keyboardNavigation.bind(this));
ON HIDE
this.<ul or div element here>.removeEventListener('keydown', this.keyboardNavigation.bind(this));
and the callback is like so
function keyboardNavigation(e) {
console.log('foo');
}
NOTE: "this" is an object to which the div and the ul are both properties of, and the callback function is actually a method of that object.
QUESTION 1:
Why is the keydown event not working when I attach it to either the ul itself or the parent div?
Anyway, since these did not work, I decided to attach the listener to the document.
ON SHOW
document.addEventListener('keydown', this.keyboardNavigation.bind(this));
ON HIDE
document.removeEventListener('keydown', this.keyboardNavigation.bind(this));
Same callback.
Now, while this works, I noticed that the event listener is not removed from the document.
I later noticed that another keydown event listener I had attached to the document for another task, is also not removed when that task is done, while it should.
QUESTION 2:
Why are the event listeners not removed? I cannot understand what I am doing wrong, I am removing the exact same callback on the exact same event as were those that were added.
Any help will be much appreciated.
NOTE:
I have tried doing it with jQuery's .on() and .off() instead, as suggested here, although I do not want to use jQuery, yet same thing is happening.
My thoughts:
1 Is it because the DIV or UL isn't getting the keyboard events because the don't have focus? Whereas the document is always getting the bubbled events?
To test this, click in the DIV/UL and type and see if the keyboard events get triggered then.
I think binding to the document - if you want the user to be able to just start typing after clicking - is the right thing to do here.
2 Is this because you are not removing the same handler you created? You should retain a reference to the handler you create with the first bind call and pass this reference in to the remove call - otherwise you're creating another (different) handler and asking to remove that.
E.g.:
var f = this.keyboardNavigation.bind(this);
document.addEventListener('keydown', f);
document.removeEventListener('keydown', f);
Im trying to remove a row. But i can't figure it out really.
First of all I've got a button that'll add a new row, that works.
But I want to give the user the possibility to remove the just added row.
The row has an 'div' inside what acts as an deletebutton. But the deletebutton doesn't work?
I'm I missing something?
Greet,
Juki
function addrow() {
$("#container").append("<div id=\"row_added\"><div class=\"deletebutton\" id=\"delbuttonnumber\"></div><div id=\"addedcolor\" class=\"colorcube\"></div></div>");
}
// deleterow the row
$(".deletebutton").click(function() {
rowclrid = "#" + $(this).parent().attr("id");
$(rowclrid).remove();
});
My guess is that you have assigned the click handler before adding the new content, so the handler is not attached to this particular element. You can use .delegate() to listen for events on all elements below a particular parent element, whether or not they already exist:
$('#container').delegate('.deletebutton', 'click', function(){
$(this).parent().remove();
});
This listens for all click events that happen inside the element #container using a feature of the DOM called event bubbling, then checks to see if they happened on a .deletebutton element, and, if so, calls the handler.
Note also the simplified code inside the handler.
I think what you need to do is use the live method. This will add the events for any new item that is added to the DOM, not just the ones that exist when you set the click handler.
// deleterow the row
$(".deletebutton").live('click', function() {
$(this).parent().remove();
});
You also don't need to get the row by getting the ID - it's simpler in the way above.