Using:
$('#foo').data('events').click
We are able to access an iterative object of click handlers added to the element '#foo' but only when they were added with .bind()
Is there a way to get the handlers for an event added with .live()?
Is there any other way to know if an element has a click handler assigned?
live events are added to the document. Use
$(document).data('events').click
The above will return an array of objects containing information about each bound click handler. Each of these objects has a selector property containing the selector that was used at the time of binding with $(selector).live(.., ..).
Any of these selectors that matches the element with id foo will get triggered when #foo is clicked. Note that the selector does not have to be exactly #foo for that to happen. There are many other selectors that can be used to target an element. For example if #foo was a <p>, then a live click handler such as
$("p").live("click", function..)
will also target #foo.
Here's one approach. Loop through each object, and see if any of the elements matching the selector property include #foo.
var handlers = $(document).data('events').click;
// jQuery quirk: $.map callback takes arguments (obj, index) and
// $(..).map takes callback arguments as (index, obj)
var fooClickHandlers = $.map(handlers, function(handler) {
if($(handler.selector).is('#foo')) {
return handler;
}
return null;
});
// fooClickHandlers is a list of all handlers that will fire on #foo click
Related
I have to write a code that run click event on all inputs with the same class without a loop and jquery.
What I come up with is :
document.body.addEventListener('click', function (click) {
if (click.target.className == 'abc') {
document.frame.screen.value += this.value;
}
});
and click works but I got undefined instead of value that clicked input contain.
and click works but I got undefined instead of value that clicked input contain.
Because you've used this instead of click.target when getting the value; you wanted to use click.target:
document.frame.screen.value += click.target.value;
// Here -----------------------^^^^^^^^^^^^
this in your handler will be document.body. You've correctly used click.target when checking the class, but not when getting the value.
Some notes:
FWIW, the usual name for the event parameter in an event handler is event or e, not click.
Elements can have multiple classes, which will all be in className. If that's a possible issue for you, you might look at .classList.contains("abc") instead. (classList is available on all modern browsers, and you can polyfill it on obsolete ones.)
It's not an issue for input elements, but in future if you want to do this with elements that can have descendant elements, you might need to have a loop to handle the possibility the click was on a descendant of your target element:
var node = event.target;
while (!node.classList.contains("abc")) {
if (node === this) {
return; // The click didn't pass through a matching element
}
node = node.parentNode;
}
// Use it here
I've a statically created table:
<table id="table" style="width:100%">
<tbody id="tbody">
</tbody>
</table>
I've dinamically created some elements:
var tbody = document.getElementById('tbody');
for (var i = 0; i < 8; i++) {
var tr = document.createElement('tr');
for (var j = 0; j < 8; j++) {
var td = document.createElement('td');
td.appendChild( createDiv(i,j)); // div id is = i + ' ' + j
tr.appendChild(td);
}
tbody.appendChild(tr);
}
But now I'm trying to add a callback function for each div, but this is not working. I think that the problem is with the jquery on function but I don't know how to solve it.
for(var x=0;x<8;x++){
for(var y=0;y<8;y++){
$(document.body).on('mousedown', '#' + x + ' ' + y, function(){
var audio = document.getElementById('audio');
audio.currentTime = 0;
audio.play();
});
}
}
When I try to do the same with static elements it works fine, does anybody know what is happening? Thanks
There are other answers here that are correct in their answer, but I wanted to add a bit more clarification.
The purpose of jQuery's on() is to attach event handlers to selected elements. The purpose of the selector parameter is to create a delegated handler. From the jQuery documentation:
The handler is not called when the event occurs directly on the bound element, but only for descendants (inner elements) that match the selector.
In addition:
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time.
(I would recommend you read the whole section on Direct and delegated events by the way.)
In any case, for your particular example, you want to build your DOM in such a way that there is a top-level element that is guaranteed to exist at the time the delegated event is attached. It may be your table, or a div element above your table. You could also attach to the body or the document, but, it is better to attach the event to the closest element that will be guaranteed to exist per this documentation:
Attaching many delegated event handlers near the top of the document tree can degrade performance. Each time the event occurs, jQuery must compare all selectors of all attached events of that type to every element in the path from the event target up to the top of the document. For best performance, attach delegated events at a document location as close as possible to the target elements. Avoid excessive use of document or document.body for delegated events on large documents.
In your particular case, it appears that the table is a guaranteed element. Because of that, you can attach to that and delegate the divs that are inside. (Of course, appropriate adjust your selectors to get the correct divs.) Assuming you want all divs to bubble up, then your attachment would be something like this:
$('#table').on('mousedown', 'div', function(e) {
console.log('Do some stuff here.');
});
Of course, you'll want to do this inside the document ready handler to ensure that your elements are present.
Also, be aware that IDs cannot start with a number in the HTML 4 spec. If you are developing HTML 5, however, IDs can basically be anything as long as they are unique, don't contain any spaces, and are at least a single character.
$(document.body).on('mousedown', '#tbody td', function(e){
//TODO::add code here
});
Need not bind event to every td dom.
Regarding your armada of event handlers.
Use 3 steps to make it 1 handler for all the dom elements:
Make the sequenctial number part of the id, to have them distinguishable.
Then only instantiate one eventhandler for the body mousedown call. No more for in for loop.
Distinguish via the event object (argument of your event callback), which id was clicked. (i think it was event.target or the alike)
Regarding the usage of this like pointed out in the comment, it might be generally useful to reference the id of an dom element that refers to a domain object. Thus the explicit id can directly relate to the underlying resource identifier( pk ...).
Creating a delegate for each #id is overkill
You can directly attach the click event to each ID in the loop or simple create a single delegate event listener.
$("#table").on("click", "div", function(e){
// use div.class to limit delegate
// split id, pull values from the dom or innerText
var el = this;
var id = this.id;
});
I am simply appending an element that is on the DOM like:
$("#div_element").append('test');
Right after I append it I need access to the element I just made in order to bind an click function to it, I tried:
$("#div_element").append('test').click(function(){alert("test")});
But the above didn't work. I could uniquely id the element but that seems like a bit to much work when perhaps there is a way I can get the element right after I append it.
You can do this:
var el = $('test');
$("#div_element").append(el);
el.click(function(){alert("test")});
// or preferrably:
el.on('click', function(){alert("test")});
The append function accepts two types of arguments: a string or a jQuery element.
In case a string is passed in, it will create a jQuery element internally and append it to the parent element.
In this case, you want access to the jQuery element yourself, so you can attach the event handler. So instead of passing in the string and let jQuery create an element, you have to create the element first and then pass it to the append-function.
After you've done that, you still have access to the jQuery element to be able to attach the handler.
var $a = $('<a />', {href:"#"})
.text("test")
.on('click', function(e) {
alert('Hello')
})
.appendTo('#div_element');
http://jsfiddle.net/33jX4/
Why not save a reference to the new element before you append it:
var newElement = $('test');
$("#div_element").append(newElement);
newElement.click(function(){alert("test")});
The last element would be the new element
$('a:last','#div_element').on('click',function(){
// do something
});
Add identity to that element then use it as follows
$("#div_element").append('<a id="tester" href="#">test</a>');
$('#tester').on('click', function(event) {
console.log('tester clicked');
});
You can attach event to element when you create it --
var ele =$("<a href='#'>Link</a>");
ele.on("click",function(){
alert("clicked");
});
$("#div_element").append(ele);
Just attach the click handler to the anchor BEFORE you append it.
$("#div_element").append($('test').click(function(){alert("test")}));
After html is entered into a container from a ajax response I would like to bind an event to various elements. I know this can be achieved by running addEventListener or on+event=function(){} right after the html is inserted.
My problem is that I am unsure of the best method to do so with dynamic content, whereas the data passed into the event is different each time.
For example, the following html is loaded into a container:
<button id="myButton">go</button>
Now, I need to bind an onclick function to the button element that contains data that was rendered on the remote side - the onclick function would be something like:
myFunction($data1,$data2,$data3);
whereas $data1,$data2,$data3 are variables with the dynamic data.
One way I can have this function bound to the button is by outputting a script to be evaluated after the HTML data is inserted into the container, so the HTML output would go like this:
<button id="myButton">go</button>
<script>document.getElementById('myButton').addEventListener('click',function(){myFunction(<?php echo $data1.','.$data2.','.$data3 ?>)});})</script>
Is there anyway I can achieve the result from the above code in a more flexible way without having to output that script line for every element and for each request?
A way that I thought of is to have a bind function that is called after every request is completed, and in this function every element that needs an event bound is stored in an array. A loop goes through the array and binds the appropriate event and function - but this gets complicated with dynamic data. Any ideas?
Use your own form of event delegation:
var container = document.getElementById("container");
container.addEventListener("click", function (e) {
e = e || window.event;
var target = e.target || e.srcElement;
if (target.tagName === "BUTTON") {
// execute handler code for buttons
}
}, false);
Where the container element is the closest, stable (not being added/removed from the DOM) element that these dynamic elements/buttons are being added to at some level.
The event is bound once to one containing element, but is triggered for any click event that bubbles up from descendants (the default behavior of click events).
This will simply check if the tagName of the element is "button". This is pretty broad, but if this is the thing you want to filter out, that's what you can use. If you want to use a class, add a specific class (maybe "special-class") to the dynamic buttons and use:
if (~(" " + target.className + " ").indexOf(" special-class ")) {
// execute handler for buttons with class "special-class"
}
If you need to pass specific data with the buttons/elements, add a specific data-* attribute that contains it, to the buttons when generating them:
<button id="whateverId" data-data1="$data1" data-data2="$data2" data-data3="$data3">go</button>
And in the event handler where you know it's the targeted buttons, you can use:
var data1 = target.getAttribute("data-data1");
var data2 = target.getAttribute("data-data2");
var data3 = target.getAttribute("data-data3");
Reference:
http://webdesign.tutsplus.com/tutorials/htmlcss-tutorials/all-you-need-to-know-about-the-html5-data-attribute/
http://caniuse.com/dataset
How would I add a class to an object of a specific class upon click? The elements that should gain an extra class contain the "date" class.
$(".date").bind("click",addClass());
function addClass(){
//objectClicked.className+=""
}
I'm having trouble figuring out how to identify the exact element that was clicked.
In a jQuery event handler, this is bound to the source element of the event, so your can use $(this).addClass('yourClass'); to add the new class to the clicked element.
$(".date").bind("click", addClass);
function addClass() {
$(this).addClass('yourClass');
}
Also, watch out that you don't invoke the addClass function in the call to bind. That won't work. You need to pass the function itself as I have.
Though FishBasketGordo answer is a working solutions, you can also do it this way :
$(".date").click(function() {
$(this).addClass("yourClass");
});