JavaScript: capturing events regardless of element - javascript

Is there any existing mechanism by which I can add an event listener to 'focus' for all the DOM elements on the page that have this event? If not, how might I do that?
I'd like to console.log(something) any time any DOM element fires an event. How might I do this?
EDIT: Without any framework please :)

You can bind the event to the body or html element. Or any other element which encloses all of your html.
Or if you want to use jQuery you could do something like
$("*").bind("focus", function(e){
console.log("something");
})

Events "bubble" up through the DOM, so you should be able to bind a listener to document, body, html, or any other parent element (e.g. a div) and listen for every event triggered by elements that it contains.
For example, using JQuery, you could do it like this:
$(document).bind('focus', function(e) { console.log(e); });
This will log every focus event, no matter what element initially triggers the event.

You could try using the :input pseudo selector in jQuery.
$(':input').focus(function(e){
console.log(e);
});
This will only attach to the input elements which is probably what you're looking for anyway.

Something like this should work (with jQuery).
$("input").focus(function(){
console.log($(this).attr("id"));
});
Here's a live example:
http://jsbin.com/ipiciz/edit#javascript,html,live

Related

trigger event globally in jquery

I am binding a custom event on div. I want to trigger that event globally without specifying target element.
edit:
Right now I am binding my custom event with div but it can be bind with any of tag. So instead of trigger event with selector. I want to trigger it globally.
I want to avoid repetition like
$('p').trigger('customevent')
$('div').trigger('customevent')
var g= document.getElementsByTagName('div')
$('div').bind('alwaysListen',function(){
$(this).hide()
});
$('a').click(function(){
$.event.trigger('alwaysListen');
});
Here's the fiddle.
Event will be bubbling across DOM nodes up and down anyway, so in some way it;s anyway global;
That's why you can do :
$(document).on('alwaysListen', function(){
//do stuff
});
Here is a link to you updated jsfiddle: https://jsfiddle.net/fa1s9e0s/7/

Document click not in elements jQuery

Using jQuery how does one detect clicks not on specific elements, and perform an action consequently?
I have the following JavaScript
$('#master').click(function() {
$('#slave').toggle();
});
$(document).not('#master','#slave').click(function() {
$('#slave').hide();
});
and I cannot see where I am going wrong logically. You can see a live example here
Since you're binding to the click event on the document, you can use event.target to get the element that initiated the event:
$(document).click(function(event) {
if (!$(event.target).is("#master, #slave")) {
$("#slave").hide();
}
});
EDIT: As Mattias rightfully points out in his comment, the code above will fail to identify click events coming from descendants of #master and #slave (if there are any). In this situation, you can use closest() to check the event's target:
$(document).click(function(event) {
if (!$(event.target).closest("#master, #slave").length) {
$("#slave").hide();
}
});
Does this code do what you want? (not entirely sure if I understood correctly)
$('body').on('click', '*:not( #master, #slave )', function() {
$('#slave').hide();
});
http://jsfiddle.net/gZ4Hz/8/
Event delegation has long been supported natively by jQuery. The difficulty lies in creating the appropriate selector. Originally, delegate was used, but more recently the delegate form of on should be used.
The purpose of event delegation is to listen to events on child elements and invoke the bound event handlers on those elements as though they had been bound to the child element, instead of the parent. This means that instead of binding handlers to every element in the DOM, you're binding a handler to every element in the initial selection (document is a single element). This also makes for a simple way to use a single selector to bind to an ever changing set of elements, as new elements will propagate their events to document whether or not they existed when the initial event handler was bound:
$(document).on('click', '*:not(#master, #master *, #slave, #slave *)', function (e) {
//this will reference the clicked element
});
Additionally, note that I not only said the elements must not be #master or #slave, they must not be children of #master or #slave either.
Another thought, it may not be working because your browser may not be rendering body at 100% height; Try adjusting your base css to fix height of body and then a couple other thoughts.
e.stopPropagation(): Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.
So if you change the first click code to the following:
$('#master').click(function(e) {
e.stopPropagation();
$('#slave').toggle();
});
Then you could change the call sign of the second too:
$("body, body *").not('#master, #slave').click(function(e) {
$('#slave').hide();
});
And that should cover it. Give it a try! or see this jsFiddle
Fredrik's answers works for elements already present in the document, but it didn't work for elements fetched by ajax calls.
I tried the following and it works for me. Sharing the code for future ajax coders.
$(document).on('click',function(event) {
if (!$(event.target).closest("#selector").length) {
if ($('#selector').is(":visible"))
$('#selector').slideUp();
}
});
Would have posted it as a comment but I don't have enough reputation for that.
$('.clickable-row').on("click",function(){
window.location = $(this).data('href');
return false;
});
$("td > a").on("click",function(e){
e.stopPropagation();
});
or
jQuery(document).ready(function($) {
$('.clickable-row').on("click",function(){
window.location = $(this).data('href');
return false;
});
$("td > a").on("click",function(e){
e.stopPropagation();
});
});

jquery using $.on for added dom elements?

I am a bit confused, I have a bunch of elements that get added via jquery using a ajax call and I want to attach a click handler to them (there could be a lot).
But I have no idea how to even begin this, I looked at .on and it is really confusing. I want to attach a click event handler for a certain class so that when I click on it, I get the this.id and then do stuff with it.
What you're trying to do is called event delegation.
You want to set the event listener on a higher element in the DOM that'll never change, but only fire off the event handler if the child element that has been clicked matches a specific selector.
Here's how it's done with jQuery's .on():
$(document).on('click', '.your-selector', function(){
alert(this.id);
});
P.S. You could probably apply the event listener to an element lower down in the DOM tree...
This will get you the id of a clicked element with the class "test"...
$(".test").on("click", function() {
var id = $(this).attr("id")
});
You'll need to run that after the ajax call returns. It will only bind the click event to elements that exist when it runs, so it's no good at document.ready.

How to bind to all click events, check for an attribute.... Efficiently?

I want to create a binding that captures all click events. And then if the item clicked has a "data-track" attribute do something...
What is the efficient way to do this? Can I bind at the body and let all the events bubble up. Any suggestions on how and how to do this efficiently?
Thanks
You should aim for simplicity over performance: Let jQuery do the work for you, and assume that the jQuery devs are better at optimizing JS than you unless you can prove otherwise.
Use the has attribute jQuery selector to setup a live click handler for all elements with the data-track attribute:
$('[data-track]').live('click', function () {
});
Attach click event handler at the document level using delegate with attribute selector [data-track].
$(document).delegate('[data-track]', 'click', function(){
//Do something here
});
Why don't you bind click events to ONLY items with a data-track attribute?
$('[data-track]').click(function() {
var data_track = $(this).attr('data-track');
//code here
});
I would go like this:
$('*[data-track]').click(function(ev){
// do something
});
or (if some such content coming from Ajax)
$('*[data-track]').live('click', function(ev){
// do something
});
Do you have to capture all click events? If you're only doing something if it has a "data-track" attribute, I believe you should be able to do:
$("*[data-track]").click(function(){//do something});
I'm not sure how that compares to other methods though for efficiency, although I think that since jQuery captures all events at the window level, it shouldn't make a difference.

How do I assign click handlers to each child with jquery?

<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');
});

Categories