overriding previously-bound click events - javascript

When I use this code with an element whose id is "foobar":
$("#foobar").click(function () { alert("first"); });
$("#foobar").click(function () { alert("second"); });
I get two alerts: "first" and "second" second.
How do I specify a click event that also clears out any previous click events attached to the element? I want the last $("#foobar").click(...) to erase any previously bound events.

You can unbind the events already attached to that element, and then attach the second event handler, so it will be the only one (note the unbind method).
$("#foobar").unbind("click").click(function() { alert("second"); });

$("#foobar").click(function () { alert("first"); });
$("#foobar").unbind('click').click(function () { alert("second"); });
Notice the unbind() method. It does exactly what it sounds like.

Related

How to wrap multiple dynamic eventListeners into one?

I just started to learn js and need a little help: I have the following function:
//SET CHAT BEHAVIOR
function chatSettings() {
console.log('ChatSettings called')
function BtnAndScrollBar(texteditor) {
console.log('BTNAndScrollBar called');
const sendBtn = $('.cl.active').find('.sendBtn');
const attachBtn = $('.cl.active').find('.attachBtn');
console.log(sendBtn)
}
function sendAndDeleteMessage(send) {
console.log(send);
}
var sendBtn = $('.cl.active').find('.sendBtn');
sendBtn.mousedown(function () {
sendAndDeleteMessage(this);
});
var textEditor1 = $('.cl.active').find('.chatTextarea');
textEditor1.on('focus change mousedown mouseout keyup mouseup', function (){
console.log(this);
BtnAndScrollBar(this)
});
}
$('document').ready(function () {
console.log('hello');
$('.tabs').tabs();
chatSettings();
});
I prepared a js.fiddle - As you can see from console.log when clicking into the textarea, the eventListener always listens to #cl1, even if .cl.active switches along with the according TAB.
The events in the textarea are just relevant, if .cl is active. My target is to wrap all three eventListener into one and apply the event to the textarea in the active stream, but all I tried went wrong... Can anyone help? #Dontrepeatyourself #DRY
$(".chatTextarea").on(
'focus change mousedown mouseout keyup mouseup',
function (this) {
//this.id can contain the unique id
greatFunction(this);
});
This will bind event individually with unique id found with this keyword and also wraps all event listener into one function but this is better when you want to process each event with same functionality
please let me know if this helps.
Peace
$(".cl textarea").on('focus change mousedown mouseout keyup mouseup', function () {
greatFunction(this)
});
Tada!
P.S. Is there a reason greatFunction is defined inside window.onload?
Try using $(document).ready function to load code when the page loads.
Also use $('textarea #cl1').on to get the textarea with the #cl1 or whichever id you want to use and then call the function after using the .on.
Hope this helps!
Let me know if it works!
$(document).ready(function () {
function greatFunction(elem) {
//do stuff
}
$('textarea').on('focus change mousedown mouseout keyup mouseup', function () {
greatFunction(this)
});
}
First off, I changed the onload to bind with jQuery, so all your logic is doing jQuery bindings, rather than swapping back and forth between jQuery and vanilla javascript. Also, doing an actual binding removes an inline binding.
Next, the binding has been condensed into a single delegate event listener. Since you eluded in your comments that it wasn't working for the active element after the active was moved or added, this reflected that you were dealing with dynamic elements. Delegate event listeners are one way to handle such things.
Delegate event listeners bind on a parent element of the elements that will change, or be created. It then waits for an event to happen on one of it's children. When it gets an event it is listening for, it then checks to see if the element that it originated from matches the child selector (second argument) for the listener. If it does match, it will then process the event for the child element.
Lastly, I added some buttons to swap around the active class, so you could see in the snippet that the event handler will start working for any element that you make active, regardless of it starting out that way.
$(window).on('load', function () {
function greatFunction (elem) {
console.log(elem.value);
}
$(document.body).on(
'focus change mousedown mouseout keyup mouseup',
'.cl.active .chatTextarea',
function () {
greatFunction(this);
}
);
$('.makeActive').on('click', function () {
$('.active').removeClass('active');
$(this).closest('div').addClass('active');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="cl1" class="cl active"><textarea class="chatTextarea">aa</textarea><button class="makeActive">Make Active</button></div>
<div id="cl2" class="cl"><textarea class="chatTextarea">bb</textarea><button class="makeActive">Make Active</button></div>
<div id="cl3" class="cl"><textarea class="chatTextarea">cc</textarea><button class="makeActive">Make Active</button></div>

Why I cannot change button event with JQuery .click() function?

Say I have a button whose id is "btn" and I add an event to the button as:
$(document).ready(function() {
$("#btn").click(function(){
$("#label1").html((new Date()).getSeconds());
$("#btn").click(function () {});
};
})
where #label1 is a label tap supposed to show the current second.
I wish by click the button at the first time, current second will shown in the label1. And for following click on this button, nothing happen. But what I got is every time the button is clicked, new current second is shown in label1. What's wrong?
Use one() to bind event
$("#btn").one('click', function(){
$("#label1").html((new Date()).getSeconds());
});
Note that $("#btn").click(function () {}); does not unbind the event. It binds click event on that element one more time, so next time when the button is clicked two event handlers will be called one to update the html and other empty function that does nothing.
To unbind the event, off() can be used, but in this case one() is preferred.
$("#btn").on('click', function () {
$("#label1").html((new Date()).getSeconds());
$(this).off('click');
});
You can simply use .one().
Attach a handler to an event for the elements. The handler is executed at most once per element per event type.
$(document).ready(function() {
$("#btn").one('click', function(){
$("#label1").html((new Date()).getSeconds());
});
})
At-present you are binding another click handler using $("#btn").click(function () {});
Hello you can remove the click Listener the following way.
$(document).ready(function() {
$("#btn").click(function(){
$("#label1").html((new Date()).getSeconds());
$('#btn').off('click');
});
})

Intercept and prevent all click events if element has "disabled" class

I am really tired of this pattern:
$("#moveButton").click(function() {
if ($(this).hasClass("disabled")) {
return;
}
//do something
});
I want to intercept all click events for elements, that have class "disabled" dynamically added.
I tried this:
$('input,a,div').click(function(event){
if ($(this).hasClass("disabled")) {
event.preventDefault()
event.stopPropagation();
}
});
but somehow it is not working.
This script is on the top of my page.js
UPDATE
The pitfall is that 'disabled' class can be added dynamically.
So ones you have already added event listener to a button, there have to be a solution to INTERCEPT all its click handlers and check if this element is disabled now. Than if it is, stop this event to be catched by handlers.
Just filter out those elements then ?
$('input,a,div').not('.disabled').on('click', function(){
// do stuff
});
if the class is added later, you can use a delegated event handler, and if you really want to return false for all elements that has that class or are within such an element:
$('input,a,div').on('click', function(e) {
if ( $(e.target).closest('.disabled').length ) return false;
});
EDIT:
as noted above, you can filter out classes added later in the event handler, if the handler is delegated, like this example:
//bind an event handler to all DIV element that does NOT have a .disabled class
$(document).on('click', 'div:not(.disabled)', function() {
alert('ok');
});
// even if we add the class later, the event handler above will filter it out
$('.test').eq(1).addClass('disabled');
EDIT
use this code
$('input,a,div').click(function(event){
if ($(this).hasClass("disabled")) {
return false;
}
});
SOLVED:
I have found two ways of interception:
1) Not an interception. Exactly as #adeneo said, we can use .on( with test method when attaching event handlers:
$(document).on('click', 'div:not(.disabled)', function() {
alert('ok');
});
see his answer for more details and upvote his answer if you find this helpful.
2) We can put this code ON TOP for executing first, but make sure you add it when DOM is rendered:
$("a,div,input").click(function(event){
if($(this).hasClass('disabled')){
event.stopImmediatePropagation()
}
});
And this will prevent all existing .click, .on('click', and .live('click' handlers from being executed. If they have no other parameters.
This solution is good if you already have tons of handlers and don't want to rewrite it.
EXAMPLE
You can use the pseudo class :disabled:
$('input:disabled,a:disabled,div:disabled').click(function() {
return false;
});

jQuery bind click firing immediately

I have a drop down menu, and clicking the icon should add the class "Open" to its parent, and then clicking the menu anywhere should close it. But the function inside the bind fires when the icon is clicked. The effect being it adds the class Open, and then removes it straight away.
This is probably a simple issue, but I cannot seem to work out why the 'click' event fires straight away!?
This question may be similar but can't still can't work it out: jQuery bind event firing the event
$(function () {
$(".ui-dropdown-action").bind("click", function () {
$(this).parent()
.addClass("Open")
.bind("click", function () {
$(this).removeClass("Open");
});
});
});
I think you might have a problem with the click event bubbling up the DOM tree. Which is why click is also being fired on the parent.
if you pass in the event object as an argument for the first bind and call event.stopPropagation() as follows
$(function () {
$(".ui-dropdown-action").bind("click", function (event) {
event.stopPropagation();
$(this).parent()
.addClass("Open")
.bind("click", function () {
$(this).removeClass("Open");
});
});
});
should fix your issue.
You can pass the event argument and stop the bubbling of the event .. Try this
$(function () {
$(".ui-dropdown-action").bind("click", function () {
$(this).parent()
.addClass("Open")
.unbind().bind("click", function (e) {
$(this).removeClass("Open");
e.stopPropagation();
});
});
});
This will make sure the parent event will not fire when the icon is clicked..
Also every single time you click the icon the event for the parent is bound again which will create multiple click events .. Need to make sure you unbind and bind them again to avoid that..
It is firing right away because the click event is bubbling to the parent and then firing that selector. To fix this you could use a setTimeout() around the 2nd bind.
$(function () {
$(".ui-dropdown-action").bind("click", function () {
var parent = $(this).parent();
parent.addClass("Open");
setTimeout(function() {
parent.bind("click", function () {
$(this).removeClass("Open");
});
}, 0);
});
});
Another option would be to to a stopPropagation() on the event on your first bind, though that would prevent any other handlers from triggering on that event.
In my case, when I use something like this
$("#modal .button")[0].click(() => console.log('test'))
its doesnt work and seems like click firing immediately
Solution for me was:
const button = $("#modal .button")[0];
$(button).click(() => console.log('test'));

How to check if there is already a click/event associated to an element

lets say I have
function trigger(){
$('a.pep').each(function(){
$('a.pep').click(function(){
console.log($(this).val());
});
});
}
function push(){
$('body').append('<a class="pep">hey mate i have no trigger yet</a>');
trigger(); //now i do but the others have duplicated trigger
}
$(document).ready(function(){
$('a.push').click(function(){
push();
});
});
So it seems that the click event is being applied twice/+ because the console.log is lauched more than once by click
How can i prevent this?
The problem is that you call $('a.pep').click() lots of times. (In fact, you bind as many click handlers as there are matching elements to each element. And then you do it again every time one of them is clicked.)
You should lever the DOM event bubbling model to handle this. jQuery helps you with the on method:
$(document.body).on('click', 'a.pep', function() {
console.log('element clicked');
$(document.body).append('<a class="pep">Click handlers handled automatically</a>');
});
See a working jsFiddle.
Note that I have removed the val call, because a elements can't have a value... Note also that the on method is introduced in jQuery 1.7; before that, use delegate:
$(document.body).delegate('a.pep', 'click', function() {
Small change to your trigger function is all you need. Just unbind the click event before binding to ensure that it is never added more than once. Also, you don't need to use each when binding events, it will add the event to each item automatically.
function trigger(){
$('a.pep').unbind('click').click(function() {
console.log($(this).val());
});
}
You can check using data('events') on any element if the required event is attached or not. For example to check if click event is attached or not try this.
if(!$('a.pep').data('events').click){
$('a.pep').click(function(){
console.log($(this).val());
});
}
you should use jQuery live here because you add DOM elements dynamicly and you want them to have the same click behaviour
function push(){
$('body').append('<a class="pep">hey mate i have no trigger yet</a>');
}
$(document).ready(function(){
$('a.push').click(function(){
push();
});
$('a.pep').live('click', function(){
console.log($(this).val());
});
});
Try:
if($('a.pep').data('events').click) {
//do something
}
i think if you use live() event you dont need to make function
$('a.pep').live('click', function(){
console.log($(this).val());
});

Categories