Why does
$(document).on("keyup blur", "#my_selector", function() {
//DO SOMETHING
});
seems to work, however
$("#my_selector").on("keyup blur", function() {
//DO SOMETHING
});
Doesn't? I put them both in my ready functions, and while the above one works, the lower one doesn't. This is in context of my previous question.
If the #my_selector item is added dynamically (e.g. after an Ajax call finishes) then you may be attaching the direct event handler before the element exists in the DOM. In this case the event handler would be attached to nothing. The first one attaches a delegated event handler so it does not matter when the element appears in the DOM, the event handler would be executed.
$('selector').on('event') works like $.bind.
$(document).on('event', 'selector') works like $.live.
In other words, $('selector').on attaches an event handler to a currently existing node.
If $('#my_selector') is empty at the time of the event handler's creation, the event handler will not be attached to it.
On the other hand $(document) is always available, and you can always attach event handlers to it.
$(document).on('event', 'selector', function() { ... }) attaches an event handler to document and filters it by 'selector'. So this works just like $().live() in previous versions of jQuery, and you should use event binding in this way.
Related
I have this:
$('.task').on('click', function()
{
task_id = $(this).data('id');
console.log('Task id: ' + task_id);
});
But this doesn't work as it should when the content is reloaded via ajax. task_id value stays the same even after clicking different elements after the ajax reload. Apparently I have to bind it to the body first.
This is how it is in my code right now though (it works as expected):
$(document).ajaxComplete(function(event, xhr, settings) {
$('.task').on('click', function()
{
task_id = $(this).data('id');
console.log('Task id: ' + task_id);
});
});
But I've been told this duplicates/doubles the trigger for the .on('click') event? Is this true? How do I know then when to bind to the direct selector or bind to the document.body instead?
Which would be more efficient? Binding to body or putting the event delegation inside ajaxComplete()?
I'm a little confused too since I have other event handlers inside the same .js file but outside ajaxComplete() that seem to work just fine even after an ajax reload?
You should use .on() method with Event Delegation approach, when generating elements dynamically(content is updated via $.ajax())/manipulating selectors. then you won't need to attach event handler in ajaxComplete()
General Syntax
$(document).on('event','selector',callback_function)
Example
$(document).on('click', '.task', function(){
//Rest of your code
});
In place of document you should use closest static container.
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.
I have a click event on the body of my document:
$("body").on('click.findElem', function(e) {
e.stopPropagation();
e.preventDefault();
self.hinter(e.target);
return false;
});
It basically catches the clicked target and does something to it. However, there are some targets that already have a click event on them, and they prevent my click from being executed at all. How do I overcome that issue? I tried unbinding it, but the click doesn't even work at all to actually execute the unbinding.
e.stopImmediatePropagation() does the job, but only if your handler executes before whatever other handler exists.
Unfortunately there is no way to insert your own handler in the first position - but you can use this nasty hack if the other handlers were bound using jQuery, too: How do you force your javascript event to run first, regardless of the order in which the events were added?
If you really need this you might want to bind an event handler in capture mode using the native DOM API: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener
Capture handlers are triggered before bubble handlers (which are used by jQuery and most other scripts) so that way you have very high chance to execute your handler first.
try this and see demo
$( "body" ).on( "click", ".clickme:not(.clicked)", function( event ) {
$(this).addClass('clicked');
alert('here');
});
i tend to not use on and stick with the bind/unbind combo.
i have some pages that reload partial content and then has to rebind the events.
i tipically do something like this
$(".theobjectsiwant").unbind("click").bind("click", function() {
alert('hi there');
});
If you want/have to stick with the on() function, you shouldn't mix on() with unbind() and try a similar approach with .off("click").on("click")
Check here for a sample http://api.jquery.com/off/
Say I have an button with an id:
<input id='someButton' />
I want to attach an event listener on this button:
$('#form').on('click', '#someButton', function() {
alert("My listener called");
});
However, unbeknownst to me, someone previously wrote an event listener for this very same button:
$('#form').on('click', '#someButton', function() {
alert("Some other listener called");
});
I encountered some code that effectively does the same thing as above, and it seems like the first listener registered is the one that is used. Am I correct in assuming jQuery will always call the first event listener registered on a specific id (and only that listener)?
Incorrect. jQuery will call ALL event listeners bound to an element, in the order they were bound.
To remove an existing event handler, use .off():
$('#form').off('click'); // click event handler(s) removed
$('#form').off(); // all event handler(s) removed
Be aware that events delegated from ancestor DOM elements won't be removed this way, though.
you could use mousedown:
$('#form').on('mousedown', '#someButton', function() {
alert("My listener called");
});
Hope this help.
So, there are two important details to this question:
its inside the scope of document ready's callback function
the element that the event is attached to does not actually exist in the DOM
Here's a visual representation of the scenario
$(document).ready(function() {
$('#myNonExistentElement').on('click', function() {
//do something
});
});
Is it possible to programatically trigger that click event (via console or something else) under those circumstances?
I think the simple answer is no.
There are two cases which might, however, fit with your question:
1) If you just want to execute the event handler code, use a named function (instead of an anonymous function) and call it whenever you need to.
2) If you want to bind a click handler to an object that does not yet exist in the DOM but you know will in the future, you can use code like:
$(document).ready(function() {
$('body').on('click', '#myNonExistentElement', function() {
//do something
});
});
See the section about delegated events at http://api.jquery.com/on/
If you try to bind an event to an element that doesn't exist via jQuery (or at the very least, .on) no new event will be bound.
Sample case here.
*event code stolen from here because I'm lazy.
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.