I want an element to listen for a custom event that is actually triggered by itself. The custom event could possibly be triggered from a descendant but should then be ignored. It's important that it origins from itself. It also needs to be an event since I might need additional ancestors to listen for the events.
The .on (http://api.jquery.com/on/) method is able to provide this functionality. The selector argument can be used as filter. However this does not work to filter out the listener element itself.
In short:
-The event must be able to bubble
-The trigger and the listener is the same element
-The listener must ignore the custom event if it's triggered by an ancestors
How is this achieved?
Use case as requested
I use the jquery UI dialog widget
$el = $('#dialogDiv');
$el.on('customEvent', $el /* Won't work */, function() {
//Do whatever
});
$el.dialog({
open: function() {
$el.trigger('customEvent');
}
});
.on works fine; to ignore ancestors check e.target:
$el.on('customEvent', function(e) {
if(e.target === this) {
//Do whatever
}
});
The selector that you can pass to .on() is used for the delegate target to match elements that can handle the click event (and it should be a string, not an object).
But in your case that's not necessary because your selector and the delegate target is the same thing, so this should work as expected:
$el.on('customEvent', function(evt) {
//Do whatever
});
To detect if an event came from a descendent you would compare evt.target against the element itself.
Removing the part that doesn't work, will make it work.
$el = $('#dialogDiv');
$el.on('customEvent', function(e) {
//Do whatever
});
$el.dialog({
open: function() {
$el.trigger('customEvent');
}
});
However, you are asking for other features that a normal event might not support. You should look into setting up a jQuery special event. Check this awesome article by Ben Alman.
When it comes to your prerequisites:
An event is always able to bubble unless its propagation is hindered with event.stopPropagation() or event.stopImmediatePropagation()
The trigger and the listener is already on the same element
The listener will not know what triggered it unless you pass some an argument that can identify the element that triggered it and check if it's an ancestor
See test case on jsFiddle.
Related
I want an element to listen for a custom event that is actually triggered by itself. The custom event could possibly be triggered from a descendant but should then be ignored. It's important that it origins from itself. It also needs to be an event since I might need additional ancestors to listen for the events.
The .on (http://api.jquery.com/on/) method is able to provide this functionality. The selector argument can be used as filter. However this does not work to filter out the listener element itself.
In short:
-The event must be able to bubble
-The trigger and the listener is the same element
-The listener must ignore the custom event if it's triggered by an ancestors
How is this achieved?
Use case as requested
I use the jquery UI dialog widget
$el = $('#dialogDiv');
$el.on('customEvent', $el /* Won't work */, function() {
//Do whatever
});
$el.dialog({
open: function() {
$el.trigger('customEvent');
}
});
.on works fine; to ignore ancestors check e.target:
$el.on('customEvent', function(e) {
if(e.target === this) {
//Do whatever
}
});
The selector that you can pass to .on() is used for the delegate target to match elements that can handle the click event (and it should be a string, not an object).
But in your case that's not necessary because your selector and the delegate target is the same thing, so this should work as expected:
$el.on('customEvent', function(evt) {
//Do whatever
});
To detect if an event came from a descendent you would compare evt.target against the element itself.
Removing the part that doesn't work, will make it work.
$el = $('#dialogDiv');
$el.on('customEvent', function(e) {
//Do whatever
});
$el.dialog({
open: function() {
$el.trigger('customEvent');
}
});
However, you are asking for other features that a normal event might not support. You should look into setting up a jQuery special event. Check this awesome article by Ben Alman.
When it comes to your prerequisites:
An event is always able to bubble unless its propagation is hindered with event.stopPropagation() or event.stopImmediatePropagation()
The trigger and the listener is already on the same element
The listener will not know what triggered it unless you pass some an argument that can identify the element that triggered it and check if it's an ancestor
See test case on jsFiddle.
is there a way to get the element? i.e:
$('#obj').hover(function() { },function() { /* here, i need to know the element that triggered this out event. */ });
thanks.
It's called ev.target
function (ev) {
var target = ev.target
// target triggered event
}
Of course you may not want the target but rather want the currentTarget
The currentTarget is the element the event handler is bound to.
As for the value of this in the callback. It's generally ev.currentTarget, jQuery uses that, the current DOM4 WD uses ev.target and the current DOM4 ED uses ev.currentTarget. I belief it's generally ev.currentTarget in legacy engines.
Note that if your not using jQuery but using the IE propitiatory event system then ev.srcElement is the equivelant of ev.target
in jQuery event binding, it passed you back an event object that you can access in your function, that object has the control in it, i think its targetElement or something like that ... so change your code to $('#obj').hover(function(ev) { }
and ev.targetElement should be what you're looking for.
Assuming that there are a large number of elements throughout the site that have an unknown number and type of events bound to them.
If I need to override all of these events with one single bound event, and only that event will fire, what are some recommendations?
I would be binding the event to a click event handler, and I am using jQuery.
Thanks in advance.
You’re looking for jQuery#unbind.
To remove all event handlers on an element or a set of elements, just do:
$('.some-selector').unbind();
To unbind only click handlers, use unbind('click'):
$('.some-selector').unbind('click');
To unbind all click handlers and immediately bind your own handler after that, you can do something like this:
$('.some-selector').unbind('click').click(function(event) {
// Your code goes here
});
Note that this will only work for events bound using jQuery (using .bind or any jQuery method that uses .bind internally). If you want to remove all possible onclick events from a given set of elements, you could use:
$('.some-selector')
.unbind('click') // takes care of jQuery-bound click events
.attr('onclick', '') // clears `onclick` attributes in the HTML
.each(function() { // reset `onclick` event handlers
this.onclick = null;
});
I would like to provide a thought without removing all events all together (just override them).
If your new one single bound event (we call it "click" here) is specific to the element it binds to, then I believe you can ignore any other events simply by stopPropagation() function. Like this
$("specific-selector").on("click", ".specific-class", function (e) {
e.stopPropagation()
// e.stopImmediatePropagation()
/* your code continues ... */
});
It will stop events bubbles up, so your other events won't fire. use stopImmediatePropagation() to prevent other events attached onto the same elements as "click" does.
For example, if "mouseleave" event is also bind to $("specific-selector .specific-class") element, it won't fire, too.
At last, all other events won't fire on this element but your new "click" element.
The unsolved question is, what if other events also use stopPropagation()? ... Then I think the one with best specification wins, so try to avoid complex, too many events is final suggestion.
You can see "Direct and delegated events" on jQuery site for more information.
Looks like this is pretty simple actually:
$('#foo').unbind('click');
$('#foo').bind('click', myNewFunction);
Thanks for your responses though.
Try to use live instead of bind. Then you can easily remove live binding with die from selector which is fast operation and set another live equally fast.
$('selection here').live('..', .....); // multiple invocations
$('selection here').die();
$('selection here').live('click',.....);
DOM is not touched at all. Event condition is evaluated on event occurrence.
But generally if you just want to swap handler functions why not to do it this way:
var ahandler = function(evt) { /* first implementation */ }
$('.selector').bind('click', function(evt) { ahandler(evt); });
//and then if you want to change handlers
ahandler = function(evt) { /* new implementation */ };
This gives absolutely no cost of any changes, rebinding etc.
I have a div, I want to set it so that when I click on something else, it would hide the div.
So I did
$('body').click(function(){
if(loginOpened)
{
$('#loginWindow').animate({
'width':'0px',
'height':'0px'
},"fast");
}
loginOpened=false;
});
However, even when I click in the div itself the event is fired, is there anyway to prevent this?
You can stop it using
e.stopPropagation(); if there is a click event bound to the <div /> tag.
See event.stopPropagation()
Prevents the event from bubbling up
the DOM tree, preventing any parent
handlers from being notified of the
event.
Otherwise you can check the target of the event inside the body click. Check whether event.target is the same as your div.
See event.target
Just check the event.target. If the element that triggered the event is your div do not execute the code.
$('body').click(function(evt){
evt = evt || window.event
if ($(evt.target) != $('#loginWindow')) {
if(loginOpened)
{
$('#loginWindow').animate({
'width':'0px',
'height':'0px'
},"fast");
}
loginOpened=false;
}
});
Yes, but of course Microsoft and the rest of the world came to different conclusions about how to do it. This site gives a good clear rundown of what's needed: http://www.quirksmode.org/js/events_order.html .
I don't use jQuery but the jQuery way appears to be event.stopImmediatePropagation(); as seen in this question: jQuery Multiple Event Handlers - How to Cancel? .
A couple of changes from John's code:
$('body').click(function(ev){
// jQuery means never having to say "window.event"!
// Also, code's cleaner and faster if you don't branch,
// and choose simple breaks over more complex ones
if(!loginOpened) return;
// Lastly, compare using the DOM element;
// jQuery objects never compare as the "same"*
if (ev.target == $('#loginWindow').get(0)) return;
$('#loginWindow').animate({
'width':'0px',
'height':'0px'
},"fast");
loginOpened=false;
});
If trapping it in the body event doesn't work for you, you can just add a simple event handler to the div:
$('#loginWindow').click(function (ev) { ev.stopPropagation(); });
I was going to say return false, but that would prevent other things from firing off the div. stopPropagation just keeps the event from bubbling outward.
I could be really picky, of course...
//Delegation via the document element permits you to bind the event before
// the DOM is complete; no flashes of unbehaviored content
$(document).delegate('body', 'click', function(ev){
//You only have one instance of an id per page, right?
if(!loginOpened || ev.target.id == 'loginWindow') return;
//quotes and px? not necessary. This isn't json, and jQ's smart
$('#loginWindow').animate({width:0,height:0},"fast");
loginOpened=false;
});
* Don't believe me? Try:
jQuery('#notify-container') == jQuery('#notify-container')
Then try
jQuery('#notify-container').get(0) == jQuery('#notify-container').get(0)
I would like to fire an event when anything on the page is clicked, and then process normally. For example a click would be fired, I would see if the target matched something, alert if it did, and then have the click event continue (no preventDefault()).
$(document).click(function(e) {
// e.target is the element which has been clicked.
});
This will handle all click events unless a handler prevents the event from bubbling up (by calling the stopPropagation() method of the event object).
$("body").click(function (event) {
// Your stuff here
}
3 options for you:
This is how .live() in jquery works. Everything bubbles to the top, and it matches the selector you set.
http://api.jquery.com/live/
A more efficient way to do it is using .delegate, or providing a context to .live() so you don't have to bubble to the top.
http://api.jquery.com/delegate/
If you want to do it manually, bind 'click' to the document, and use .closest() to find the closest matching selector:
http://api.jquery.com/closest/
It's all the same concept, event delegation as mentioned already.