The .on() method in jQuery will either match on the matched element if no selector is provided or only on it's children if ther is a selector.
Is it possible to combine these two behaviours to end up with a single .on() statement that matches both the element and any specified children?
Example: http://jsfiddle.net/mwvdlee/YFF2k/
You can simply bind the event handler to the parent and use event.target [docs] to the get actual target element of the event:
$('.foo').on('click', function(event) {
console.log('click', event.target);
});
Since events bubble up (that's how event delegation works in the first place), every click on a descendant of .foo will trigger the event handler of .foo (unless the event was stopped somehow of course).
By default the events are bubbling up. Just avoid passing a delegate selector and attach the event-handler on the parent. When children will get clicked, the event should bubble up to the parent and the event will get fired.
DEMO: http://jsfiddle.net/YFF2k/2/
$('.foo').on('click', function (e) {
console.log('click', e.target);
});
you can try something like:
$('.foo').children().andSelf().on('click', function (event){
//something
});
Related
Most people know how to bind "click' event to dynamically added element with
$('#main').on('click','.link',function(){ //some code here });
Where .link is a dynamically added element. But how the code above should look like when i want to fire function only on first click? Yes, i know about .one(), but the question is to merge .one() with .on().
jQuery docs for show .one() and .on() are the same as of 1.7:
.one( events [, selector ] [, data ], handler )
.on( events [, selector ] [, data ], handler )
If you just want it to fire on the first click, you can unbind the listener after the execution.
$('#main').on('click', '.link', function() {
$('#main').off('click', '.link');
// do whatever you need here
});
.one()
Description: Attach a handler to an event for the elements. The handler is executed at most once per element per event type.
$('#main').one('click','.link',function(){
//some code here
});
I dont think it is possible straight-away to create delegated on() which will be fired at most once( i.e one()) because of the way delegated handler is wired up.
on(): 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.
Thus the event will always be fired on descendent, even you detach the handler for the current element .link using .off() method inside the handler body.
However you can still achieve this by maintaining a list of DOM elements as a closure and match the list before doing actual code work.
var elements = [];//list of elements which is responded to events at once
$('#main').on('click', '.link', function() {
if(matched){//match $(this)/ uniqueIdentifier in 'elements' array
// prevent default and stopPropagation
return;
}
elements.push($(this));//or push something like 'id' to uniquely identify current element
//..codes
});
I have two jquery functions that work together, one depends on a class, another removes the class.
Once it is removed I would expect the functionality to stop working, but it carries on?
Whats going on?
Here is the fiddle, try it out for yourself.
<div class="container disabled">
Go to Google
</div>
<label>
<input type="checkbox" />Enable link</label>
The JS
$('.disabled > a').click(function (e) {
e.preventDefault();
e.stopPropagation();
alert('should stop working');
});
$('input[type=checkbox]').change(function () {
$('.container').removeClass('disabled');
});
It looks like you want to be using delegated event handlers rather than static event handlers. Let me explain.
When you run a line of code like this:
$('.disabled > a').click(function (e) {
this installs an event handler on any objects that match the selector at that moment in time. Those event handlers are then in place forever. They no longer look at what classes any elements have. So changing a class after you install a static event handler does not affect which elements have event handlers on them.
If you want dynanamic behavior where which elements respond to an event does depend upon what classes are present at any given moment, then you need to use delegated event handling.
With delegated event handling, you attach the event "permanently" to a parent and then the parent evaluates whether the child where the event originated matches the select each time the event fires. If the child no longer matches the select, then the event handler will not be triggered. If it does, then it will and you can add/remove a class to cause it to change behavior.
The general form of delegated event handlers are like this:
$("#staticParent").on("click", ".childSelector", fn);
You ideally want to select a parent that is as close to the child as possible, but is not dynamic itself. In your particular example, you don't show a parent other than the body object so you could use this:
$(document.body).on("click", ".disabled > a", function() {
e.preventDefault();
e.stopPropagation();
alert('should stop working');
});
This code will then respond dynamically when you add remove the disabled class. If the disabled class is present, the event handler will fire. If it is not present, the event handler will not fire.
Working demo: http://jsfiddle.net/jfriend00/pZeSA/
Other references on delegated event handling:
jQuery .live() vs .on() method for adding a click event after loading dynamic html
jQuery .on does not work but .live does
Should all jquery events be bound to $(document)?
JQuery Event Handlers - What's the "Best" method
jQuery selector doesn't update after dynamically adding new elements
Changing the class after the event handler is bound has absolutely no effect as the event handler is not suddenly unbound, it's still bound to the same element.
You have to check for the class inside the event handler
$('.container > a').click(function (e) {
if ( $(this).closest('.container').hasClass('disabled') ) {
e.preventDefault();
e.stopPropagation();
}
});
$('input[type=checkbox]').change(function () {
$('.container').toggleClass('disabled', !this.checked);
});
FIDDLE
When the selector runs, it gets a list of elements including the one in question and adds a click event handler to it.
Then you remove the class - so any subsequent jQuery selectors wouldn't get your element - but you have already attached the event so it will still fire.
The selector you have used runs on the line you declared it - it isn't lazily initialized when clicks happen.
I have an issue after adding a element dynamically it doesn't have the click event, so i have the following:
$(".myclass > li").click(function () {
...
});
so basically when i click on LI element something should happen and it works.
But when i add a new LI element to myclass which is UL element, this newly added element doesn't call this function.
My question how do i rebind or bind this newly element to this function ..?
Because the other elements when i click on them they work, but only the new element doesn't ... i suppose it is that the binding happens on postback or somethnig but in my case there is no postback :/
You need to use Event Delegation. You have to use .on() using delegated-events approach.
i.e.
$(document).on('event','selector',callback_function)
In your case
$(document).on('click', '.myclass > li', function () {
...
});
OR if you want to apply to ALL list items:
$(".myclass").on('click', '> li', function () {
...
});
need to use event delegation to support dynamic elements
$(".myclass").on('click', '> li' function () {
...
});
Since the element is added after you bind the event, it doesn't have the handler attached and the bind function doesn't listen for any new elements that might be added.
Thus, you need to use event delegation. When an event triggers, it will bubble up all the way to the parent document. Using the jQuery .on() function you can listen for events that have bubbled up from their target.
In your case, you should use the following:
$(parent).on("click", "li", function() { ... });
The above will listen for click events that occur on li elements and bubble up to parent. Inside the event handler this will refer to the li element on which the event triggered. In case you don't know the parent, you can listen on document.
You can learn more about the .on() function here.
When I bind a handler to a element
$('tr').on('click', handler)
And Then when I trigger the element's click event, nothing happen
$('tr').trigger('click')
instead the element within the can response to the event
$('tr td:first').trigger('click')
So does it mean that <tr> element isn't clickable?
What does your handler function do? It seems to work fine for me:
function handler(e){
alert(e.target);
}
// attach event
$('tr').on('click', handler);
// manually trigger click
$('tr').trigger('click');
Live example.
<tr>'s are DOM objects, so you should be able to attach events to them
stopPropagation() will also help.
$('tr').click(function(e){
e.stopPropagation();
});
<ul>
<li>Hello..</li>
</ul>
$('input').click(function(){
$('ul').prepend($('<li>Another Hello...</li>').click()); // not working [1]
$('ul').prepend('<li>This is hello appending...</li>').children(':first').click(); // this is working [2]
});
$('ul li').live('click', function(){
console.log('New li clicked...');
});
Why the [1] code snippet working? Is there any other ways to resolve this the same task? I want to fire the click event at the time of prepend().
N.B: here prependTo() can be used, but is it possible do the same job using prepend().
Because the new element, $('<li>Another Hello...</li>'), is not part of the DOM tree (the document) yet, so the event cannot bubble up to fire the event handler bound with .live().
.live() binds the event handler to the document root and works because events are bubbling up the DOM tree. That means, first the event handler of the element where the event originated is called, then the event handler of its parent and so on, for every ancestor, until it reaches the document root.
But if the element is not added to the document, it has not parent node, so the event cannot bubble up.
You could use .prependTo() [docs] instead:
$('<li>Another Hello...</li>').prependTo('ul').click();