I'm using
$(document).on('click', '.mySelector', function () {
//do something
});
To delegate events to buttons.
Next I'm using .clone(true) to copy div which containing few buttons with delegated in to it events.
My question is how do I remove events form selected new created buttons?
I'm tried:
$(document).unbind('click', $(myNewDiv).find('.mySelector'));
Somehow it's removing events from all $('.mySelector') in whole document not only from this inside 'myNewDiv' object.
I have seen documentation of jQuery .off() and .undelegate() and they accept only string like selector (my div can't have any unique ID).
Is any option to remove events from selected elements inside jQuery object when they are delegated to document?
You can add a class to your clones:
var $clone = $original.clone(true).addClass("clone");
And reject that class in your delegated handler:
$(document).on("click", ".mySelector:not(.clone)", function() {
// Do something...
});
$(document).on('click', '.mySelector', function(){
//do something
});
the code above means, "attach a click handler to the document, so whenever any element that corresponds to the '.mySelector' selector is clicked, fire the handler".
whenever you clone an element, you clone its class as well, therefore it will suit the '.mySelector' too.
the handler that you have delegated is attached to the document and not to the elmenets themselves. in order for the new elements to not fire the handler, you must make them not fit the selector. so either change their class to '.mySelector2' after cloning, or whatever.
Related
I've attached delegated event handlers to a number of elements on the page using a single selector. As the events are triggered for individual elements, I'd like to turn off only that element's event handler based on some conditional logic. That means I won't necessarily want to disable the event on the very first click. But I can't figure out how to do it without turning off all of them.
HTML:
<button>One</button>
<button>Two</button>
<button>Three</button>
JS:
$(document).on('click', 'button', function(ev) {
// doesn't work because argument needs to be a string
$(document).off('click', $(ev.target));
// doesn't do what I want b/c turns off events on all buttons, not just this one
$(document).off('click', 'button');
// doesn't work because event is on document, not button
$(ev.target).off('click');
});
jQuery's off documentation says I need to provide a string as the second argument, not a jQuery object ($(ev.target)), but if I provide a string, there's no value that refers only to the item clicked.
From jQuery's off 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 "**".
So how do I turn off a delegated event handler for a specific element?
Here's a JSFiddle of the code above
UPDATE: Added a few examples of options that don't work, based on initial answers provided.
After having read thru on the web, the answer is you can't! You can either remove all or none. A workaround could be something like the following.
$(document).on('click', '.btn', function (ev) {
alert('pressed');
$(this).removeClass("btn");
});
Demo#Fiddle
Sample HTML:
<button class="btn">One</button>
<button class="btn">Two</button>
<button class="btn">Three</button>
In addition to what lshettyl said (the current top post) - an additional work around is to bind a new event listener directly to the element that you're trying to remove the listener and call stopPropagation() therein.
What this will do is prevent the event from traveling up the DOM and reaching the event handler that is initially bound to the document. Also this will allow you to keep some functionality on the button click, such as an alert to the user that this button has already been clicked - or something to that effect.
$(document).on('click', 'button', function(ev) {
// Your logic to occur on button click
// Prevent further click on just this button
$(this).click(function(event) {
event.stopPropagation();
}):
});
Question: Do you have to use the delegated events? LIke LShetty said, it is not possible to remove a delegated event for a single element. You either remove the entire event delegation, or leave it. You could try using a different selector instead like in this example
$('button').on('click', function(ev) {
$('#output').append('Clicked! ');
$(this).off('click');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<button>One</button>
<button>Two</button>
<button>Three</button>
<div id="output"></div>
If I clone an element with events .clone(true) and append it within the same page. Can I trigger the same 'live' click event on both.
For example, if I build my own select menu using 'ul' and 'li' elements and add a 'live' click' event on it's class e.g. '.selectOption'. Can I make the original element change when the cloned one does?
I don't really have a code example, but I have run into trouble with this before. The original stays the same if you select one of the options. I have tried triggering a click on the original, but that does not work either.
I don't understand why the event will not make both change. It is pointing to both because they have the same class and structure.
Instead of using .delegate() or .live(), you should try using .on() instead. Let's say you are cloning the element with the class name item, then you can use the following code to bind an event, say, a click event:
$(document).on('click', '.item', function() {
// Do magic here that changes things in both the original item and its cloned counterpart
});
How .on() works is that it listens for events to bubble up the DOM tree until it reaches your selected element of interest, and in this case, document. The caveat is that the element you are listening on event bubbling has to be present in the DOM when jQuery is executed, and document is the safest way to do it. Of course you can also use .on() on other static elements that are present in the DOM, such as <body>.
The OP has furnished with additional information. It seems that OP wants the changes done to one element to propagate to its cloned counterpart, and not simply binding the same handlers to the cloned elements.
$(document).ready(function () {
var $selectMenu = $('.selectMenu');
$selectMenu.on('click', 'li', function () {
$(this).css('background','red');
});
$selectMenu.clone(true).appendTo('body');
});
In this case, I would advocate the use of indexes (with .index()) for DOM transversal in the context of the element's parent.
$(document).ready(function () {
var $selectMenu = $('.selectMenu');
$selectMenu.on('click', 'li', function () {
$(".selectMenu").find('li:eq('+$(this).index()+')').css('background','red');
});
$selectMenu.clone(true).appendTo('body');
});
See fiddle here: http://jsfiddle.net/teddyrised/4Jxv2/2/
Also, some possible improvements:
Add/remove classes instead of directly manipulating inline CSS of the element
Use .on() so that you can bind events that are not originally bound to the element before cloning.
See revised function below:
$(document).ready(function () {
// Clone first, worry about binding events later
$('.selectMenu').clone(true).appendTo('body');
// Bind events
$(document).on('click', '.selectMenu li', function() {
$('.selectMenu')
.find('li:eq('+$(this).index()+')')
.addClass('highlighted');
});
});
where the class .highlighted can be used to declare the background color :) See fiddle here: http://jsfiddle.net/teddyrised/4Jxv2/3/
I am using jQuery and i want to unbind the click event of dom element wherever a particular class is added to that dom element.
This particular class is added and removed dynamically using add class and remove class functions. So if the class is added on dom element and id that dom element has a click event i want to unbind the click event.
Why are you trying to bind and unbind the event? It may be simpler to do something like this:
$(document).on("click", "#element:not(.someClass)", function () {
// this function will only run if the clicked element doesn't have the class someClass
});
How about this:
$('.someClass').unbind('click');
or
$('.someClass').off('click');
You have the answer in your title.
I'm not sure what the context here is. How do you bind it in the first place and why do you want to unbind it?
An alternative way is to just ignore the click event if the element has a certain class.
$(selector).on("click", function(event) {
// Returning false will automatically call event.stopPropagation() and event.preventDefault()
if ($(this).hasClass("some-class")) return;
// Other code
});
I have a few generated div's on my page listing events on a calender, they all have the same class "fc-event-inner". I would like to add a onclick to these div's but am struggling to get this right.
This is what iv tried, no onclick is added and no errors on page.
$(document).ready(function () {
$('.fc-event-inner').each(
function (element) {
Event.observe("click", element, EventClick);
}
);
function EventClick() {
alert("You clicked an event")
}
});
This is an example of a generated event div:
<div class="fc-event-inner">
<span class="fc-event-title">Requested<br>by Santa</span>
</div>
Use the delegate version of on
$(document).on("click", ".fc-event-inner", function(){
/// do your stuff here
});
This catches the click at the document level then applies the class filter to see if the item clicked is relevant.
Example JSFiddle: http://jsfiddle.net/BkRJ2/
In answer to comment:
You can access the clicked element via this inside the event function. e.g.
$(document).on("click", ".fc-event-inner", function(){
var id = this.id; // Get the DOM element id (if it has one)
var $this = $(this); // Convert DOM element into a jQuery object to do cool stuff
$this.css({'background-color': 'red'}); // e.g. Turn clicked element red
});
*Note: You should never have to run an Each in order to catch events on multiple items that have a common class.
You do not need each() to bind event to elements with specific class, just selector is enough. Use jQuery on() with event delegation it will bind event to those which are generted after the binding code.
$(document).on("click", ".fc-event-inner", function(){
alert("click");
});
Delegated events
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, you can use delegated events to
avoid the need to frequently attach and remove event handlers, jQuery doc.
<div class="fc-event-inner">
<span class="fc-event-title">Requested<br />by Santa</span>
</div>
Your JS:
<script>
$(document).ready(function () {
$('.fc-event-inner').on("click", EventClick);
function EventClick() {
alert("You clicked an event")
}
});
</script>
http://jsfiddle.net/UBhk9/
Some explanation:
Because you are using a class(it may be used multiple times, in contrast to an id) it will work for all the elements with this class name. The .on method will attach the event handler(in this example "click") to the selector(the class .fc-event-inner). If you want to remove events bounds you've to use the .off() method and if you only want to attach the event once you can use the .one() method.
i'm trying to register the second click on a link, by adding a new class and finding it with jQuery. But it won't change the class after the 1st click.
Hope it makes sense and thank you in advance.
// Listen for when a.first-choice are being clicked
$('.first-choice').click(function() {
// Remove the class and another one
$(this).removeClass('first-choice').addClass('one-choice-made');
console.log('First Click');
// Some code goes here....
});
// Make sure the link isn't fireing.
return false;
});
// Listen for when a.one-choice-made are being clicked
$('.one-choice-made').click(function() {
// Remove the class and another one
$(this).removeClass('one-choice-made').addClass('two-choice-made');
console.log('Second Click');
// Some code goes here....
});
// Make sure the link isn't fireing.
return false;
});
At load, .one-choice-made does not exist, so when you call $('.one-choice-made'), it returns an empty jQuery object, hence the click() handler is not added to anything.
What you want to do is attach the handler to something that will always exist, which will respond to the click event (i.e. a parent/ancestor element). This is what $.on() will do for you when called in a delegated handler syntax (i.e. with a filter selector):
$(document).on('click', '.one-choice-made', function() {
// my second function
}
In this case, jQuery attaches a special handler to document, which watches for click events that propagate to it from children elements. When it receives a click, jQuery looks at the target of the click and filters it against the selector you provide. If it matches, it calls your function code. This way, you can add new elements with this class at any time, as long as they are children of the elements from the selector(s) you applied .on() to. In this case, we used document, so it will always work with new elements.
You can pare this down to a known permanent parent element to reduce click events, but for simple cases document is fine.
NOTE: In the same way, removing the class first-choice will not have any affect on whether the first click handler is called, because the handler is applied to the element. If you remove the class, the element will still have the handler. You will need to use a delegated handler for that as well:
$(document).on('click', '.first-choice', function() {
// my first function
}
Demo: http://jsfiddle.net/jtbowden/FxqX9/
Since you're changing the class you need to use .on()s syntax for delegated events.
Change:
$('.one-choice-made').click(function() {
to:
$(document).on('click', '.one-choice-made', function() {
Ideally you want to use an element already in the DOM that's closer than document, but document is a decent fallback.