Unbinding event handler that was bound with .on() - event-handling

I'm trying to unbind some event handlers that were bound with .on(), but nothing seems to work:
HTML:
<div class='parent'>
<a id='test-1' class='test'>Test 1</a>
<a id='test-2' class='test'>Test 2</a>
<a id='test-3' class='test'>Test 3</a>
</div>
<hr>
<a class='unbind'>Unbind Test 1</a>
JS:
$('.parent').on('click', 'a.test', function(e){
alert('click');
});
$('a.unbind').click(function(e){
$('a#test-1').unbind('click');
$('a#test-1').off('click');
});
Fiddle:
http://jsfiddle.net/g9ucd/5/
CLARIFICATION: Per the example, I want to know if it's possible to unbind specific elements that had previously been bound with .on(), rather than just reversing the all the bindings with .off().

The jQuery API on method documentation states that the event is actually placed on the elemented it is called from, the filter selector you apply is used to then determine which elements the event is valid on. So the short answer is NO you can't unbind the even from an element that is designated by the filter selector.
However, have you considered working around this by constraining your selector further?
You could remove the test class from the a element and then by that scenario it would no longer meet the filter selector's criteria and thus be untied to the event.
Just a thought.
Here's my fiddle and below is the snipped that i changed.
$('a.unbind').click(function(e){
$('a#test-1').removeClass('test');
});

How about this:
var clickie = function(e){
alert('click');
}
$('.parent').on('click', 'a.test', clickie);
$('a.unbind').click(function(e){
$('.parent').off('click', 'a.test', clickie);
});
Thing is, you never set a handler on a#test-1 - you set it on .parent. You can't remove what you didn't set. If you need to remove a handler from a#test-1, you must not use the live functionality: $('.parent a.test').on('click', clickie) will bind your function onto the elements themselves, so you can off them individually.

You can try this
$('a.test').on('click', function(e){
alert('click');
});
$('a.unbind').click(function(e){
$('a#test-1').unbind('click');
$('a#test-1').off('click');
});

You need to add more logic to it:
$('.parent').on('click', 'a.test', function(e){
// retrieve switch value:
var disable_calls = $(this).data('disable-calls') || false;
if (!disable_calls){
// your logic here...
alert('click!');
};
});
$('a.unbind').click(function(e){
// disable call by turning the switch:
$('a#test-1').data('disable-calls', true);
});
Event handlers are attached to the outer element (.parent) and jQuery gives you a shortcut for actually checking event.target (you do that by supplying selector within .on() call). To alter that logic, you need to add your own special handling, or eg. make sure that selector is no longer matched:
$('.parent').on('click', 'a.test.calls-enabled', function(e){
alert('click!');
});
$('a.unbind').click(function(e){
// disable call by turning the switch:
$('a#test-1').removeClass('calls-enabled');
});

A variation on #ermagana's and #Tadeck's answers is simply to use the :not selector on the initial delegated binding. That way, you can "unbind" certain elements by explicitly disabling them with an extra class.
(In this case, I'll use the .disable class, which would give extra benefit of disabling them visually if you were using Bootstrap etc..)
$('.parent').on('click', 'a.test:not(.disabled)', function(e){
alert('click');
});
$('a.unbind').click(function(e){
$('a#test-1').addClass('disabled');
});

Related

Reset a Marketo Form upon submission

I have an embedded Marketo form I am using on my site.
When I click submit I want the form to reset to its original state.
What do I need to add to my code for this, and better yet where can I find this in the Marketo documentation?
Here's my current code
<script src="//app-sjg.marketo.com/js/forms2/js/forms2.min.js"></script>
<form id="mktoForm"></form>
<script>
MktoForms2.loadForm("//app-sjg.marketo.com", "819-OWT-537", 1404);
</script>
<script>
MktoForms2.whenReady(function (form){
form.onSuccess(function(values, followUpUrl){
$('#confirmform').modal('show');
return false;
});
});
</script>
The Marketo Form object does not have the reset functionality, but luckily enough, javascript has such a native .reset() method on the HTML form elements. This .reset() method will restore a form element’s default values.
Having said that, the only thing to do within the .onSuccess() callback is to grab the HTML form. Calling the .getFormElem() method of the Marketo Form object, will give us the jQuery wrapped form element, so with form.getFormElem()[0] finally we get the form node, on which we can call .reset().
Here is the sample code:
<script src="//app-lon06.marketo.com/js/forms2/js/forms2.min.js"></script>
<form id="mktoForm"></form>
<script>
// The fourth argument of the `.loadForm()` can be used as an onReady callback.
MktoForms2.loadForm("//app-sjg.marketo.com", "819-OWT-537", 1404, function(form) {
form.onSuccess(function(values, followUpUrl){
// $('#confirmform').modal('show');
console.log(form);
// .getFormElem() returns the jQuery wrapped form element
var formElement = form.getFormElem()[0];
// .reset() is a native javascript method.
formElement.reset();
// If boolean `false` is returned then the visitor
// will NOT be forwarded to the follow up page!
return false;
});
});
</script>
Note: the good thing is, that all the important hidden fields (e.g.: formid and munchkinId) will remain intact.

can't remove specific event handlers when attached to document with .on()

Here's a simple fiddle to demo my situation...
http://jsfiddle.net/UnsungHero97/EM6mR/17/
What I'm doing is adding an event handler for current & future elements, using .on(). I want to be able to remove these event handlers for specific elements when something happens; in the case of the fiddle, when the radio button is selected, the event handler for the blue elements should be removed and clicking those elements should not do anything anymore.
It doesn't seem to be working :(
How do I remove the event handler attached to document that I created with .on() for those specific blue elements?
The signature for your .on() and .off() has to match.
These two do not match so the .off() call won't find matching event handlers to remove:
$(document).on('click', '.btn', function() {
update();
});
$(document).off('click', '.blue');
Note, the selector passed to .on() and .off() is different.
When using the dynamic form of .on() (where you pass a selector as an argument to .on()), you can't remove just part of the items. That's because there's only one event handler installed on the root element and jQuery can only remove the entire thing or not at all. So, you can't just .off() some of the dynamic items.
Your options are to remove all the event handlers with:
$(document).off('click', '.btn');
and, then install a new event handler that excludes the items you don't want such as:
$(document).off('click', '.btn:not(.blue)');
Or, teach the event handler itself how to ignore .blue items:
$(document).on('click', '.btn', function() {
if (!$(this).hasClass('blue')) {
update();
}
});
Be careful of how you attach your events; this works fine for me:
$('.btn').on('click', function() {
update();
});
$('#disable').on('change', function() {
$('.btn').off('click');
});
Only way seems to be:
$('#disable').on('change', function() {
$(document)
.off('click', '.btn')
.on('click', '.btn:not(.blue)', update);
});

Create jQuery ui resizable instance using selector added to DOM by jQuery

I'm trying to start a jquery ui resizable instance, but using a selector added to the DOM by jquery itself. This is a basic example of my script:
HTML:
<div class='lyr'></div>
jQuery:
// Add class
$('lyr').addClass('fixed');
// Resizable
$('.fixed').resizable({
aspectRatio: true,
handles: 'all'
});
I've thought about using something along the lines of live() or bind() but I have no event to bind to. Any help appreciated.
I have used the LiveQuery plugin - http://brandonaaron.net/code/livequery/docs in the past to be able to target elements added to the dom, like in your case.
If I've got this right, you want anything on the page which has the class "fixed" to be resizable, even if the class is added after the page has loaded? You're right that live, bind and delegate won't help here.
I can think of two possibilities, neither lovely.
First, set up a live "mouseenter" event which will make the element resizable if it wasn't before:
$(body).delegate(".fixed", "mouseenter", function(ev) {
var target = $(ev.target);
if (target.data("resizable")) return;
target.resizable({
aspectRatio: true,
handles: 'all'
});
})
This gets us round the problem of having no event to bind to.
Alternatively, you could monkeypatch jQuery.fn.addClass:
var classRe = new RegExp(c + className + \b);
._addClass = jQuery.fn.addClass;
jQuery.fn.addClass = function(className) {
if (classRe.test(classname)) {
if (this.data("resizable")) return;
this.resizable({
aspectRatio: true,
handles: 'all'
});
}
jQuery.fn._addClass.apply(this, arguments);
}
Of course this will only work if the class is added through the addClass method.
Also in your example,
$('lyr').addClass('fixed');
Should probably be:
$('.lyr').addClass('fixed');

How to implement event order in parent/child elements using jquery

I have a parent & child elements in my web page where both have separate event handlers defined for them. I have tested in firefox, where the event handler for parent element gets executed first. I want it to execute the other way - child element's event handler getting executed first.
I have read about making use of bind, stopPropagation, preventDefault etc. make that happen but I am a bit confused as a to how to get this working? Can somebody shed some light on this topic?
Here is how I am implementing the event handling....
$('#Sidebar ul li .DeleteList').live('click', function(e) {
alert("I was deleted");
});
$('#Sidebar ul').delegate('li', 'click', function(e) {
alert("I was selected");
});
Why not be consistent and just use .live() for both? :D
$('#Sidebar ul li .DeleteList').live('click', function(e) {
alert("I was deleted");
});
$('#Sidebar ul li').live('click', function(e) {
alert("I was selected");
});
This way 'deleted' gets triggered first.
fiddle: http://jsfiddle.net/c9sBD/

jquery selection with .not()

I have some troubles with jQuery.
I have a set of Divs with .square classes. Only one of them is supposed to have an .active class. This .active class may be activated/de-activated onClick.
Here is my code :
jQuery().ready(function() {
$(".square").not(".active").click(function() {
//initialize
$('.square').removeClass('active');
//activation
$(this).addClass('active');
// some action here...
});
$('.square.active').click(function() {
$(this).removeClass('active');
});
});
My problem is that the first function si called, even if I click on an active .square, as if the selector was not working. In fact, this seems to be due to the addClass('active') line...
Would you have an idea how to fix this ?
Thanks
Just to give something different from the other answers. Lonesomeday is correct in saying the function is bound to whatever they are at the start. This doesn't change.
The following code uses the live method of jQuery to keep on top of things. Live will always handle whatever the selector is referencing so it continually updates if you change your class. You can also dynamically add new divs with the square class and they will automatically have the handler too.
$(".square:not(.active)").live('click', function() {
$('.square').removeClass('active');
$(this).addClass('active');
});
$('.square.active').live('click', function() {
$(this).removeClass('active');
});
Example working: http://jsfiddle.net/jonathon/mxY3Y/
Note: I'm not saying this is how I would do it (depends exactly on your requirement) but it is just another way to look at things.
This is because the function is bound to elements that don't have the active class when you create them. You should bind to all .square elements and take differing actions depending on whether the element has the class active:
$(document).ready(function(){
$('.square').click(function(){
var clicked = $(this);
if (clicked.hasClass('active')) {
clicked.removeClass('active');
} else {
$('.square').removeClass('active');
clicked.addClass('active');
}
});
});