I have a question about the binding and unbinding events to elements in Javascript. I understand this: we bind and unbind elements to a elements when we create an element and this do something so we bind an event and when the user delete this element with and action the event listener needs to be remove because the element was removed, this is was I think, so my question is I am correct? Or when and why we bind and unbind events.
Thanks.
The reasons of when and why to bind an event are too numerous to list here (probably the former is more broad than the latter).
However, 'we' as programmers use functions such as bind() so that our code may listen to events that occur on a particular element.
unbind() is used when we no longer need to receive callbacks that an element has received such an event.
As to when we use bind() and unbind() depends entirely upon the project and requirements for the event. Sometimes the events will be bound upon the creation of an element. Sometimes they'll be bound by a trigger (such as a user clicking a widget, for example), and sometimes they will be bound by the response of an AJAX call (or similar server-side callback). Similarly, we may use unbind() inside of a callback from another event, or when something happens on the server.
As you can see, there is no "definitive" answer to when we use bind() and unbind(). However, you're slightly incorrect in your statement that unbind() is used when an element is removed. That is not necessary, when the element is removed, its event bindings are automatically discarded.
Let's say we have this span:
<span id="my-span">Hello.</span>
I want to be notified when a click occurs:
var span = document.getElementById('my-span');
var alertWhenMySpanIsClicked = function () {
alert('my span was clicked');
};
span.addEventListener(
'click', alertWhenMySpanIsClicked
);
I don't want to be notified anymore:
span.removeEventListener(
'click', alertWhenMySpanIsClicked
);
Related
I've a bad-programmed library which is doing this
$(document).on('click','#keep_first_only_button', function(){
I wrote, after this, a piece of code to 'override' this bad behaviour
$("keep_first_only_button").unbind("click");
$("keep_first_only_button").on("click", selectKeepFirstOfAll);
BUT this is not working, then document.click function handler is triggered again
I cannot unbind all click events from document, because disasters will happen in the page.
Which is the right way to proceed in this situation?
EDIT: Sorry for time loosing question, I didn't see the missing '#' in my selector. I'm really sorry !
The original event handler was bound as a delegated event, so you can't remove it from $('#keep_first_only_button') itself. You need to remove it on the document level.
From the documentation:
To remove specific delegated event handlers, provide a selector
argument. The selector string must exactly match the one passed to
.on() when the event handler was attached. To remove all delegated
events from an element without removing non-delegated events, use the
special value "**".
In other words, to unbind a delegated event, you should just use the same set of arguments you used to bind them but pass them to off instead. Since the bound function is anonymous you can't reference it, so you'll have to settle with unbinding all delegated event handlers bound to #keep_first_only_button on the document level:
$(document).off('click', '#keep_first_only_button');
EDIT: Looks like the problem was just the missing hash. Odd, I thought you couldn't unbind delegated event handlers using a regular .off() call...
$("#keep_first_only_button")...
Missing the hash?
For anyone wondering ...Mattias Buelens is correct.
If you have the element bound like
$(document).on("click","#element",function(){ });
And want to shut it off later, you have to do it as:
$("#element").click(function(e) {
$(document).off('click', '#element');
});
If you want remove event with out consider selector use
$(document).off("click","**");
Below two scenario give me the same behavior. But What is the difference technically? (I put the below code in the last section of script tags in the body.)
$(document).ready(function() {
$('.collapse').collapse({toggle: false});
$(document).on('click', '#expandAllLessons', function() {
$('div.accordion-body').collapse('show');
});
$(document).on('click', '#collapseAllLessons', function() {
$('div.accordion-body.collapse').collapse('hide');
});
});
or
$(document).ready(function() {
$('.collapse').collapse({toggle: false});
});
$(document).on('click', '#expandAllLessons', function() {
$('div.accordion-body').collapse('show');
});
$(document).on('click', '#collapseAllLessons', function() {
$('div.accordion-body.collapse').collapse('hide');
});
Thanks.
More or less, it's doing the same thing.
With the use of .on() with a child selector, you're using event delegation to bind any future events to any elements that match that selector. document is the very tippy top of the DOM tree (and available upon script execution), so your event delegation works.
.ready() waits until the DOM has assembled, so you can, more reliably, directly bind events using methods like .click(), .hover(), etc.
So your first example is just waiting for the DOM to assemble, then delegating the event. The second example is just delegating the event immediately upon script execution.
From jQuery's documentation regarding .on():
Direct and delegated events
The majority of browser events bubble, or
propagate, from the deepest, innermost element (the event target) in
the document where they occur all the way up to the body and the
document element. In Internet Explorer 8 and lower, a few events such
as change and submit do not natively bubble but jQuery patches these
to bubble and create consistent cross-browser behavior.
If selector is omitted or is null, the event handler is referred to as
direct or directly-bound. The handler is called every time an event
occurs on the selected elements, whether it occurs directly on the
element or bubbles from a descendant (inner) element.
When a selector is provided, the event handler is referred to as
delegated. The handler is not called when the event occurs directly on
the bound element, but only for descendants (inner elements) that
match the selector. jQuery bubbles the event from the event target up
to the element where the handler is attached (i.e., innermost to
outermost element) and runs the handler for any elements along that
path matching the selector.
Whenever you do a function, regardless of whether it's $(document).ready(function(){}); or something else, all the contents inside that function can only read stuff that's at its level or above it (unless you're using return functions).
The top paragraph means that all your code won't be executed until it's loaded, but it also means that it's nested code. Nested code means certain variables and functions won't be readable from outside. Example:
function bob(){
function sandy(){
function joe(){
alert("I can access anything written by sandy, bob or ray!");
}
}
}
function ray(){
alert("I can't see anything from anybody but bob!");
}
Look at the comments first. After jQuery 1.7 on can delegate events as well:
"The .on() method attaches event handlers to the currently selected
set of elements in the jQuery object. As of jQuery 1.7, the .on()
method provides all functionality required for attaching event
handlers. For help in converting from older jQuery event methods, see
.bind(), .delegate(), and .live()."
So before jQuery 1.7 this is the correct answer:
First is better because, document ready event is triggered when HTML document is fully loaded to DOM. And then you're sure you have all elements in place, and you can bind events to them.
But if you bind event before loading '#expandAllLessons' element to DOM, then it will simply not work, as jQuery selector will not find any elements, and will not bind this event anywhere.
After 1.7 both will work almost in the same way. Almost, because in first case, when you trigger event before document will be ready, it will not be executed. In second example it will be executed, because it was attached when script was loaded.
I am using jQuery v.1.7.1 where the .live() method is apparently deprecated.
The problem I am having is that when dynamically loading html into an element using:
$('#parent').load("http://...");
If I try and add a click event afterwards it does not register the event using either of these methods:
$('#parent').click(function() ...);
or
// according to documentation this should be used instead of .live()
$('#child').on('click', function() ...);
What is the correct way to achieve this functionality? It only seems to work with .live() for me, but I shouldn't be using that method. Note that #child is a dynamically loaded element.
Thanks.
If you want the click handler to work for an element that gets loaded dynamically, then you set the event handler on a parent object (that does not get loaded dynamically) and give it a selector that matches your dynamic object like this:
$('#parent').on("click", "#child", function() {});
The event handler will be attached to the #parent object and anytime a click event bubbles up to it that originated on #child, it will fire your click handler. This is called delegated event handling (the event handling is delegated to a parent object).
It's done this way because you can attach the event to the #parent object even when the #child object does not exist yet, but when it later exists and gets clicked on, the click event will bubble up to the #parent object, it will see that it originated on #child and there is an event handler for a click on #child and fire your event.
Try this:
$('#parent').on('click', '#child', function() {
// Code
});
From the $.on() documentation:
Event handlers are bound only to the currently selected elements; they
must exist on the page at the time your code makes the call to .on().
Your #child element doesn't exist when you call $.on() on it, so the event isn't bound (unlike $.live()). #parent, however, does exist, so binding the event to that is fine.
The second argument in my code above acts as a 'filter' to only trigger if the event bubbled up to #parent from #child.
$(document).on('click', '.selector', function() { /* do stuff */ });
EDIT: I'm providing a bit more information on how this works, because... words.
With this example, you are placing a listener on the entire document.
When you click on any element(s) matching .selector, the event bubbles up to the main document -- so long as there's no other listeners that call event.stopPropagation() method -- which would top the bubbling of an event to parent elements.
Instead of binding to a specific element or set of elements, you are listening for any events coming from elements that match the specified selector. This means you can create one listener, one time, that will automatically match currently existing elements as well as any dynamically added elements.
This is smart for a few reasons, including performance and memory utilization (in large scale applications)
EDIT:
Obviously, the closest parent element you can listen on is better, and you can use any element in place of document as long as the children you want to monitor events for are within that parent element... but that really does not have anything to do with the question.
The equivalent of .live() in 1.7 looks like this:
$(document).on('click', '#child', function() ...);
Basically, watch the document for click events and filter them for #child.
I know it's a little late for an answer, but I've created a polyfill for the .live() method. I've tested it in jQuery 1.11, and it seems to work pretty well. I know that we're supposed to implement the .on() method wherever possible, but in big projects, where it's not possible to convert all .live() calls to the equivalent .on() calls for whatever reason, the following might work:
if(jQuery && !jQuery.fn.live) {
jQuery.fn.live = function(evt, func) {
$('body').on(evt, this.selector, func);
}
}
Just include it after you load jQuery and before you call live().
.on() is for jQuery version 1.7 and above. If you have an older version, use this:
$("#SomeId").live("click",function(){
//do stuff;
});
I used 'live' in my project but one of my friend suggested that i should use 'on' instead of live.
And when i tried to use that i experienced a problem like you had.
On my pages i create buttons table rows and many dom stuff dynamically. but when i use on the magic disappeared.
The other solutions like use it like a child just calls your functions every time on every click.
But i find a way to make it happen again and here is the solution.
Write your code as:
function caller(){
$('.ObjectYouWntToCall').on("click", function() {...magic...});
}
Call caller(); after you create your object in the page like this.
$('<dom class="ObjectYouWntToCall">bla... bla...<dom>').appendTo("#whereeveryouwant");
caller();
By this way your function is called when it is supposed to not every click on the page.
What all events can be triggered programmatically using jQuery? Also is there any important differences to be remembered when one is doing event triggering using jQuery Vs a natural way of it being triggered?
Every event can be programmatically fired, just use the callback-less version of it.
Example:
$('#button').click(function() { alert('event hanlder'); });
$('#button').click(); // generate the event
About your second question, there should be no difference between the native and jQuery event handlers.
One thing that is neat though is that jQuery binds this to the element that received the event, inside the callback (this doesn't happen in native event handlers):
$('#button').click(function() { alert(this); }); // here 'this' == document.getElementById('button');
Warning: the element referenced by this is not "jQuery augmented". If you want to traverse or modify it with jQuery goodness you'll have to do something like var $this = $(this);
You should know the differences between trigger and triggerHandler in jQuery.
trigger
trigger attempts to replicate the natural event as best as it can. The event handler for the event being triggered get's executed, but the default browser actions will not always be replicated exactly. For example $('a#link).trigger('click'); will execute the javascript function bound to the links click event handler, but will not redirect the browser to the href of the anchor, like a normal click would. EX: http://jsfiddle.net/AxFkD/
All the short forms of the trigger call behave exactly like trigger IE. click(), mouseup(), keydown(), etc
triggerHandler
triggerHandler prevents bubbling up ( EX. http://jsfiddle.net/LmqsS/ ), it avoids default browser behaviour and just executes the events callback, and it returns the return value of the event handler instead of a jQUery object for chaining.
You should also be aware that trigger affects all elements matched by a selector, but triggerHandler only affects the first one EX: http://jsfiddle.net/jvnyS/
You can trigger any event programmatically. But most of the events cannot be simulated as the natural event using programmatic triggers.
//to trigger a click event on a button
$("buttonSelector").trigger("click");
First, for obvious reasons, you cannot trigger the ready event.
That said, events raised by trigger() behave the same way as if they were triggered by the user. In particular, the event handlers are called in the same order.
The only difference I know of is that triggered events did not bubble up the DOM tree in older versions of jQuery (that behavior was fixed in version 1.3).
this code in book jQuery in action page 131
i don't understand
.trigger('adjustName');
what is adjustName
and Simple explanation for trigger()
thanks :)
$('#addFilterButton').click( function() {
var filterItem = $('<div>')
.addClass('filterItem')
.appendTo('#filterPane')
.data('suffix','.' + (filterCount++));
$('div.template.filterChooser')
.children().clone().appendTo(filterItem)
.trigger('adjustName');
});
It is a string, the name of a custom event you defined.
E.g. it would trigger the event handler bound by:
el.bind('adjustName', function(){...});
For more information I suggest to have a look at the documentation:
Any event handlers attached with .bind() or one of its shortcut methods are triggered when the corresponding event occurs. They can be fired manually, however, with the .trigger() method. A call to .trigger() executes the handlers in the same order they would be if the event were triggered naturally by the user.
Without knowing the context of the code, I would say that calling .trigger() here has no effect, as it is called on the cloneed elements and the event handlers are only cloned if true is passed to clone.
Maybe the original jQuery manual could be helpful?
Description: Execute all handlers and
behaviors attached to the matched
elements for the given event type.
It allows you to trigger, or run, an event. For instance if you wanted the code to mimic the clicking of a button, you could write....
$("#myButton").trigger('click');
This would then run exactly as if you had clicked the button yourself.
'adjustName' is a custom event. So the trigger function is running that custom event. The custom event is assigned using the jQuery bind function.
$("#someElement").bind('adjustName', function() {/* Some Code */});
You might create a customer event for clarity. Perhaps your application opens a document, so you might want an event called 'openDocument' and 'closeDocument' assigned to the element containing the document.