jquery .off doesn't seem to work - javascript

so I'll be short: jquery .off() doesn't disable a listen I've set with .on.
html:
<span id="myspan">lol</span>
<button id="b1">jquery On</button>
<button id="b2">jquery Off</button>
js:
$("#b1").on("click", add);
$("#b2").on("click", del);
function add() {
$("#myspan").on("click", function(e) {
var a = 1;
testfunc(a, e);
});
}
function del() {
$("#myspan").off("click", testfunc);
}
function testfunc(num, event) {
alert(num);
}
So first we add to myspan the testfunc() by clicking the jquery On button. After we do that, if we click on the span, we get an alert. Next, we click the jquery off button. That is supposed to remove the listener but it doesn't. Even after that, when we click on myspan testfunc is still attached.
Why? And how can I remove it ?

Your parameters don't match
It doesn't because you bound to a different function (anonymous one). And then you're trying to unbind from testfunc... In order for your event (un)binding to work both parameters between on and off must match.
Possible workaround
If this is the only click event listener on the element, then it's be easiest way to unbind from your anonymous function by calling:
$("#myspan").off("click");
If you're binding several event handlers to click event on the same element then you can also distinguish them by providing namespaces and then use proper namespacing in off call.
$("#myspan").on("click.test", function(e) { ... });
...
$("#myspan").off("click.test");
Or use just namespace if you'd like to unbind several different event handlers that were bound using the same namespace:
$("#myspan").off(".test");

You're not binding the event handler to testfunc, you're binding it to an anonymous function, and whitin that function you're just calling testfunc, so you can't automatically unbind that.
It's either
$("#myspan").on("click", testfunc); // bind function
and then
$("#myspan").off("click", testfunc); // unbind function
or to unbind the anonymous function, just
$("#myspan").off("click"); // remove all handlers
or you can also namespace the handler
$("#myspan").on("click.test", function(e) {
var a = 1;
testfunc(a, e);
});
and to remove only that handler
$("#myspan").off("click.test");

In this simple case, replace your off call with this:
function del() {
$("#myspan").off("click");
}
You don't need to pass the handler function to the off call, and if you do, it will only remove that particular handler. However, you did not attach testfunc, but an anonymous function that just calls testfunc(). Therefore, your off call does nothing.
Also, you never assigned the variable testfunc.

Related

JavaScript preventDefault is not a fuction

I am trying to detect a click on a button using JavaScript and prevent the default action
<button onclick="myFunction(this)">Click Here</button>
function myFunction(event) {
event.preventDefault();
console.log("Function Has Run")
}
I am getting the error
event.preventDefault is not a function
Where am I going wrong?
Inside an onclick function, the value of this is the element, not the event.
event is the first argument to the onclick function.
You could do this:
onclick="myFunction(event)"
… but I'm honestly not sure if onclick attributes set up a local event variable of if this is the global event.
It is better to bind your event handlers with JavaScript instead:
document.querySelector('button').addEventListener('click', myFunction)
Then myFunction itself will be the event handler so the first argument passed to it will be the event object, and this will be the element to which the event handler is bound.
As long as you want to access the event inside, I have figured out that passing the event directly in your onclick attribute works the best.
If you wish to use a different this, you will have to bind it using bind, call or apply
Your code would look similar to this in the end:
<button onclick="myFunction.call('new this', event)">Click Here</button>
function myFunction(event) {
console.log(this); // "new this"
event.preventDefault();
console.log("Function Has Run")
}

Rebind JavaScript events and addEventListener fires twice

I have a class method which defines the event listeners. Let us use the following code snippet for simplicity.
function bindEvents() {
document.querySelector('button').addEventListener('click', (e) => {
console.log('clicked!');
});
}
// Initial event binding
bindEvents();
// Rebind events at some point for dynamically created elements
bindEvents();
<button type="button">Click</button>
Everything works fine when using bindEvents() only once, however for example calling it again in ajax callback results in listener executed twice. So this means after second bindEvents(), clicking the button will console.log() twice and so on. Is there a way I can get around this behavior?
I know I can bind the events "dynamically" on the document and check with e.target, but there is a situation where I need mouseenter/mouseleave events and I don't think it's a good idea to always have those eventListeners on the document.
I've read somewhere the following, but it seems false...
The .addEventListener method ensures that the same function reference
won't be bound more than once to the same element/event/captures
combination.
Also I have played with the options parameter from here https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener, but without success.
Excuse me if this was answered somewhere, but I failed to find answer in SO and the search engines.
UPDATE: Is there a way to overwrite existing eventListeners or old ones should be removed with removeEventListener like kcp suggested below? Is there more elegant solution to this problem at all?
The .addEventListener method ensures that the same function reference won't be bound more than once to the same element/event/captures combination.
In your case, each time you execute bindEvents() a completely new handler is passed to the click event listener since you define new function (no matter it looks the same, it is different object). To use the same handler each time you must define it outside bindEvents and pass it by name (by reference). This works as expexted:
function clickHandler(e){
alert('clicked!');
}
function bindEvents() {
document.querySelector('button').addEventListener('click', clickHandler);
}
// Initial event binding
bindEvents();
// Rebind events at some point for dynamically created elements
bindEvents();
<button>click</button>
However with jQuery I use the following approach which allows me to specify that only elements in a specific container (context or ctx) will be bound:
$.fn.bindEvents = function bindEvents(ctx){
ctx = ctx || this;
$('button', ctx).on('click', function(event){
alert(1);
});
};
$('body').bindEvents();
$('div').bindEvents();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Click</button>
<div><button>in div </button></div>
In the example above bindEvents is executed twice but the first button is bound only once since it's not in a div. While if you click on the second button it alerts twice because satisfies both contexts.
addEventListener does not overwrite existing event listeners, it simply adds a new one as the method name implies. Existing listeners must be removed using the removeEventListener method.
function onClick($event) {
console.log('clicked!');
}
function bindEvents() {
/** Remove event listener first **/
document.querySelector('button').removeEventListener('click', onClick);
document.querySelector('button').addEventListener('click', onClick);
}
removeEventListener docs
Apart from removeEventListener, You can also use Event delegation. Using this mechanism event is handler by attaching event listener to parent element.
var elem = document.querySelector('div');
elem.addEventListener('click', function(e) {
e = e || event
var target = e.target;
if (target.nodeName != 'BUTTON')
return;
console.log('clicked ' + target.textContent);
});
//Simulate addition of dynamic elements
setTimeout(function() {
var newButton = document.createElement('button');
newButton.innerHTML = 'Click 2';
elem.appendChild(newButton)
}, 2000)
<div>
<button type="button">Click</button>
</div>

how to bind again the click event for the button

I have a button on which i am attaching a click event. I have to unbind it after i click on it, and later on in my code i need to bind that click event on it again. I tried binding it again but that does not works. I can't use jquery 'live'. Is there any way to create a custom bind function on click event and then again call it ?
$(".submitButton").click(function(e){
//some functionality on click
$(".submitButton").unbind('click');
});
//somewhere ahead in my code
$(".submitButton").bind('click');
Apparently this isn't working. Is there any way to tackle this ?
Your .bind call doesn't seem correct. You haven't specified a callback.
So start by writing a function:
function handleButtonClick() {
//some functionality on click
$(this).unbind('click');
}
Notice that inside the handler I am unbinding $(this) which is the element being clicked and not all elements with class="submitButton".
and then:
$('.submitButton').bind('click', handleButtonClick);
and then later when you want to rebind:
$('.submitButton').bind('click', handleButtonClick);
and so on.
define your listener somewhere else:
function clickHandler() {
//some functionality on click
$(".submitButton").unbind('click', clickHandler);
}
$(".submitButton").bind('click', clickHandler);
//somewhere ahead in my code
$(".submitButton").bind('click', clickHandler);
When you use .bind() to bind an event handler it expects a function to be passed as well, since that's what will be executed when the event fires. Don't use an anonymous function, instead declare a named function and pass a reference to that when binding.
function handleClick(e){
//some functionality on click
$(".submitButton").unbind('click');
}
$(".submitButton").click(handleClick);
// somewhere else in your code (in reaction to some other event)
$(".submitButton").click(handleClick);
You can use jQuery.one(). Please refer below code.
$(".submitButton").one('click', clickHandler);
The first form of this method is identical to .bind(), except that the handler is unbound after its first invocation.
you can call it or bind it whenever it necessary.

Separate Event Handler for Reusability

I have a simple click handler that will alert its link's href as in:
<a id="link" href="http://www.google.com">Google</a>
$('a#link').on('click', function() {
alert($(this).attr('href'));
});
How can I separate the function (and how to call it) so that it can be called by another click handler?
function showHref() {
/* What to do here because $(this) won't resolve to <a> anymore. */
}
// I'd like a#another-link to be able to call that same function above.
<a id="another-link" href="http://www.microsoft.com">Microsoft</a>
$('a#another-link').on('click', /* How to call showHref? */);
Thanks.
You could do something like this:
function showHref() {
alert($(this).attr('href'));
}
$('a#link').on('click', showHref);
$('a#another-link').on('click', showHref);
In this code, this inside the showHref will refer to the link being clicked, since jQuery makes sure that the link being clicked is the calling context (using .call() which you may want to read up on). If, however, you were to manually call showHref, this would not refer to your link.
If you want a definition of showHref that you could both call manually, and bind through jQuery, it would probably be neatest to pass the reference as a parameter:
function showHref(link) {
alert($(link).attr('href'));
}
In that case, you'd have to adjust your listeners as follows:
$('a#link').on('click', function() {
showHref(this);
});
But it is also possible to combine selectors:
$('a#link, a#another-link').on('click', function() {
alert($(this).attr('href'));
});
You can put the function logic into a reference like this:
var handler = function () {
alert($(this).attr('href'));
};
Then you can use that reference to initialize event listeners:
$('#link').on('click', handler);
Of course, you can reuse that.
$('#some_other_link').on('click', handler);
Or call that yourself outside of an event handler context (which normally wouldn't make sense if you're fashioning an event handler function --- but it can be done with lambdas in general).
handler();
But if you want to just trigger the event on an element, you should call the corresponding event trigger function.
$('#link').click();
// or
$('#link').trigger('click');
You wrote:
function showHref() {
/* What to do here because $(this) won't resolve to <a> anymore. */
}
Umm, actually, yes it will. That's exactly the promise made by DOM events and also event handlers registered with jQuery.
FWIW, the content should just be:
alert(this.href)
There's really no need to invoke jQuery just to get the element's href attribute.

Mootools events, callable?

So I have an element that has an onClick event thusly:
var foobar = $('element').addEvent('click', function() {
// some code here
});
But I want to call the action from somewhere else in the script, would it be possible to do such a thing, i.e."
foobar.click
?
You can fire events in mootools:
$('element').fireEvent('click');
http://mootools.net/docs/core/Element/Element.Event#Element:fireEvent
In addition you can pass in parameters or a delay, chain the event to other events, or bind another element or function with the event.
If you have more than one 'click' event on the element, it will fire all of them.
Check out the docs.
Yes. From http://mootools.net/docs/core/Element/Element.Event#Element:fireEvent :
foobar.fireEvent('click');

Categories

Resources