jQuery unbind click event function and re-attach depending on situation - javascript

The code below I use to create a sliding menu. I need to know how to unbind the function attached to the click event and re-attach it some other time. (using jQuery 1.7.2)
$(document).ready(function(){
$('.section').hide();
$('.header').click(function(){
if($(this).next('.section').is(':visible'))
{
$('.section:visible').slideUp()
$('.arrows:visible').attr("src","right.gif")
}
else
{
$('.section').slideUp();
$(this).next('.section').slideToggle();
$(this).find('.arrows').attr("src","down.gif")
});
});
The code below is what I have so far
$('#printVers').click(function(){
if($('#formVersion').val() != "Print")
{
$('.header').unbind('click');
}
else
{
//else re-attach functionality?
}
});
Thanks

Simply make a named function. You can go low tech here and back to basics to unbind and reattach specific events.
function doStuff()
{
if($(this).,next('.section').is(':visible'))
...
}
$('.header').on('click', doStuff);
$('.header').off('click', doStuff);

Instead of unbind and re-bind, I suggest you to add a simple class to .header and check for the class in the click handler. See below,
$('#printVers').click(function(){
if($('#formVersion').val() != "Print")
{
$('.header').addClass('dontClick');
} else {
$('.header').removeClass('dontClick');
}
});
And in your .header click handler,
$('.header').click(function(){
if ($(this).hasClass('dontClick')) {
return false;
}
//rest of your code
If you insist on having a unbind and bind, then you can move the handler to a function and unbind/bind the function any number of time..

You can try something like this.
$('#printVers').click(function(){
if($('#formVersion').val() != "Print")
{
$('.header').addClass('clickDisabled');
}
else
{
$('.header').removeClass('clickDisabled');
}
});
And then in the click handler check for this class.
$(document).ready(function(){
$('.section').hide();
$('.header').click(function(){
if(!$(this).hasClass('clickDisabled')){
...
...
}
});
});

Why not make that top section a function, and then call it in your else statement?

You could try setting a variable as a flag. var canClick = ($('#formVersion').val() != 'Print'); Then in the click handler for your .header elements check to see if canClick is true before executing your code.
If you still want to remove the handler you can assign the events object to a variable. var eventObj = #('.header').data('events'); That will give you an object with all the handlers assigned to that object. To reassign the click event it would be like $('.header').bind('click', eventObj.click[0]);

After trying so hard with bind, unbind, on, off, click, attr, removeAttr, prop I made it work.
So, I have the following scenario: In my html i have NOT attached any inline onclick handlers.
Then in my Javascript i used the following to add an inline onclick handler:
$(element).attr('onclick','myFunction()');
To remove this at a later point from Javascript I used the following:
$(element).prop('onclick',null);
This is the way it worked for me to bind and unbind click events dinamically in Javascript. Remember NOT to insert any inline onclick handler in your elements.

You could put all the code under the .click in a separated function
function headerClick(){
if($(this).next('.section').is(':visible'))
{
$('.section:visible').slideUp()
$('.arrows:visible').attr("src","right.gif")
}
else
{
$('.section').slideUp();
$(this).next('.section').slideToggle();
$(this).find('.arrows').attr("src","down.gif")
}
}
and then bind it like this:
$(document).ready(function(){
$('.section').hide();
$('.header').click(headerClick);
});
$('#printVers').click(function(){
if($('#formVersion').val() != "Print")
{
$('.header').unbind('click');
}
else
{
$('.header').click(headerClick);
}
});

Related

jquery .off(): how to remove a certain click handler only?

I've an element with two handler bound to it:
<button class="pippo pluto">
push me
</button>
$('.pippo').on('click', function () {
alert("pippo");
});
$('.pluto').on('click', function () {
alert("pluto");
});
I'm trying to .off() only one of them, but the syntax eludes me :-( I'm trying with something among the line of..
<button class="dai">
remove
</button>
$('.dai').on('click', function () {
$('.pippo').off('click');
alert("ok, removed");
});
but this removes both the handler. So I'm trying with...
$('.pippo').off('click .pippo');
but then nothing gets removed.
So I removed the middle space:
$('.pippo').off('click .pippo');
but back to square 1: both handler gets removed.
The right syntax would then be... ?
https://jsfiddle.net/6hm00xxv/
The .off(); method allows you to target multiple selectors as well as a specific event.
$('.pippo').off() would remove all events for the .pippo selector.
$('.pippo').off('click') would remove all click events for the .pippo selector.
$('.pippo').off('click', handler) would remove all click events with that handler for the .pippo selector.
In your case the handler used to add the event listener was an anonymous function so the handlercannot be used in the off() method to turn off that event.
That leaves you with three options, either use a variable, use a namespace or both.
Its quite simple to figure out which one to use.
if( "The same handler is needed more than once" ){
// you should assign it to a variable,
} else {
// use an anonymous function.
}
if ( "I intent to turn off the event" && ( "The handler is an anonymous function" || "I want to turn off multiple listeners for this selector at once" ) ){
// use a namespace
}
In your case
your handler is only used once so your handler should be an anonymous function.
you wish to turn off the event and your handler is anonymous so use a namespace.
So it would look like this
$('.pippo').on('click.group1', function () {
alert("pippo");
});
$('.dai').on('click', function () {
$('.pippo').off('click.group1');
alert("ok, removed");
});
It would work just as well to assign you handler to a variable if you prefer.
This allows you to specify which selector, eventType and handler to remove.
var pippo_click = function (e) {
alert("pippo");
});
$('.dai').on('click', function () {
$('.pippo').off('click', pippo_click);
alert("ok, removed");
});
But as a rule you shouldn't create variables if they're not needed.
One easier alternative with jQuery is to define a namespace for your click events:
$('.pippo').on('click.first', ...);
$('.pluto').on('click.second', ...);
// Remove only the pippo listener
$('.pippo').off('click.first');
Note that your classes pippo and pluto refer to the same element so using one or the other will not change anything.
https://jsfiddle.net/6hm00xxv/2/
Ok, solved. I just had to bind the handler to document:
function showMsg(text) {
alert("showMsg called with text: " + text);
};
$(document).on('click', '.pippo', function () {
showMsg("pippo");
});
$(document).on('click', '.pluto', function () {
showMsg("pluto");
});
$('.dai').on('click', function () {
$(document).off('click', '.pippo');
alert("ok, removed");
});
https://jsfiddle.net/6hm00xxv/1/
Because you are calling .off for click event. It is removing all possible click events on that selected element. The trick is to define a handler and remove that particular handler only.
function showPluto() {
showMsg("pluto");
};
function showPippo() {
showMsg("pippo");
};
function showMsg(text) {
alert("showMsg called with text: " + text);
};
$('.pippo').on('click', showPippo);
$('.pluto').on('click', showPluto);
$('.dai').on('click', function() {
$('.pippo').off('click', showPippo);
alert("ok, removed");
});

Adding an on event to an e.currentTarget?

A variety of elements on my page have the content editable tag.
When they are clicked I do this:
$('[contenteditable]').on('click', this.edit);
p.edit = function(e) {
console.log(e.currentTarget);
e.currentTarget.on('keydown', function() {
alert("keydown...");
});
};
I get the current target ok, but when I try to add keydown to it, I get the err:
Uncaught TypeError: undefined is not a function
It's a native DOM element, you'll have to wrap it in jQuery
$(e.currentTarget).on('keydown', function() {
alert("keydown...");
});
e.currentTarget should equal this inside the event handler, which is more commonly used ?
It's a little hard to tell how this works, but I think I would do something like
$('[contenteditable]').on({
click : function() {
$(this).data('clicked', true);
},
keydown: function() {
if ($(this).data('clicked'))
alert("keydown...");
}
});
Demo
First issue is you are trying to use jQuery methods on a DOM element. Second issue is I do not think you want to bind what is clicked on, but the content editable element itself.
It also seems weird to be adding the event on click instead of a global listener. But this is the basic idea
$(this) //current content editable element
.off("keydown.cust") //remove any events that may have been added before
.on('keydown.cust', function(e) { //add new event listener [namespaced]
console.log("keydown"); //log it was pressed
});
Edited: I had a fail in code. It works fine now.
Getting your code, I improved to this one:
$(function(){
$('[contenteditable]').on('click', function(){
p.edit($(this));
});
});
var p = {
edit: function($e) {
console.log($e);
$e.on('keydown', function() {
console.log($(this));
alert("keydown...");
});
}
}
You can check it at jsFiddle
You need to wrap the e.currentTarget(which is a native DOM element) in jQuery since "on" event is a jQuery event:
$(e.currentTarget).on('keydown', function() {
alert("keydown...");
});
EDIT:
$('[contenteditable]').on('click', p.edit);
p.edit = function(e) {
$(e.currentTarget).on('keydown', function() {
alert("keydown...");
});
};
You're defining p.edit AFTER $('[contenteditable]').on('click', p.edit); resulting in an error since p.edit doesn't exist when declaring the on.
In case you don't know, you are defining p.edit as a function expression, meaning that you have to define it BEFORE calling it.

html div onclick event

I have one html div on my jsp page, on that i have put one anchor tag, please find code below for that,
<div class="expandable-panel-heading">
<h2>
<a id="ancherComplaint" href="#addComplaint"
onclick="markActiveLink(this);">ABC</a>
</h2>
</div>
js code
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
alert('123');
});
function markActiveLink(el) {
alert($(el).attr("id"));
}
here I when I click on div I got alert with 123 message, its fine but when I click on ABC I want message I want to call markActiveLink method.
JSFiddle
what is wrong with my code? please help me out.
The problem was that clicking the anchor still triggered a click in your <div>. That's called "event bubbling".
In fact, there are multiple solutions:
Checking in the DIV click event handler whether the actual target element was the anchor
→ jsFiddle
$('.expandable-panel-heading').click(function (evt) {
if (evt.target.tagName != "A") {
alert('123');
}
// Also possible if conditions:
// - evt.target.id != "ancherComplaint"
// - !$(evt.target).is("#ancherComplaint")
});
$("#ancherComplaint").click(function () {
alert($(this).attr("id"));
});
Stopping the event propagation from the anchor click listener
→ jsFiddle
$("#ancherComplaint").click(function (evt) {
evt.stopPropagation();
alert($(this).attr("id"));
});
As you may have noticed, I have removed the following selector part from my examples:
:not(#ancherComplaint)
This was unnecessary because there is no element with the class .expandable-panel-heading which also have #ancherComplaint as its ID.
I assume that you wanted to suppress the event for the anchor. That cannot work in that manner because both selectors (yours and mine) select the exact same DIV. The selector has no influence on the listener when it is called; it only sets the list of elements to which the listeners should be registered. Since this list is the same in both versions, there exists no difference.
Try this
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
alert('123');
});
$('#ancherComplaint').click(function (event) {
alert($(this).attr("id"));
event.stopPropagation()
})
DEMO
Try following :
$('.expandable-panel-heading').click(function (e) {
if(e.target.nodeName == 'A'){
markActiveLink(e.target)
return;
}else{
alert('123');
}
});
function markActiveLink(el) {
alert($(el).attr("id"));
}
Here is the working demo : http://jsfiddle.net/JVrNc/4/
Change your jQuery code with this. It will alert the id of the a.
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
markActiveLink();
alert('123');
});
function markActiveLink(el) {
var el = $('a').attr("id")
alert(el);
}
Demo
You need to read up on event bubbling and for sure remove inline event handling if you have jQuery anyway
Test the click on the div and examine the target
Live Demo
$(".expandable-panel-heading").on("click",function (e) {
if (e.target.id =="ancherComplaint") { // or test the tag
e.preventDefault(); // or e.stopPropagation()
markActiveLink(e.target);
}
else alert('123');
});
function markActiveLink(el) {
alert(el.id);
}
I would have used stopPropagation like this:
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
alert('123');
});
$('#ancherComplaint').on('click',function(e){
e.stopPropagation();
alert('hiiiiiiiiii');
});
Try out this example, the onclick is still called from your HTML, and event bubbling is stopped.
<div class="expandable-panel-heading">
<h2>
<a id="ancherComplaint" href="#addComplaint" onclick="markActiveLink(this);event.stopPropagation();">ABC</a>
</h2>
</div>
http://jsfiddle.net/NXML7/1/
put your jquery function inside ready function for call click event:
$(document).ready(function() {
$("#ancherComplaint").click(function () {
alert($(this).attr("id"));
});
});
when click on div alert key
$(document).delegate(".searchbtn", "click", function() {
var key=$.trim($('#txtkey').val());
alert(key);
});

Prevent element from animating based on previous class

$('.example').hover(
function () {
$(this).css('background','red');
},
function () {
$(this).css('background','yellow');
}
);
$('.test').click(function(){
$(this).css('marginTop','+=20px').removeClass('example');
}
);
<div class="text example"></div>
Although the class example was seemingly removed, the hover actions for it are still being applied to the element that once had that class. How can I prevent this?
http://jsfiddle.net/gSfc3/
Here it is in jsFiddle. As you can see, after executing the click function to remove the class, the background still changes on hover.
Event handlers are bound to a Node, so it doesn't matter if that Node doesn't own a specific className anymore. You would need to .unbind() those events manually, or better, use jQuerys .off() method.
So, if you can be sure that there aren't any other event handlers bound to that node, just call
$(this).css('marginTop','+=20px').removeClass('example').off();
This will remove any event handler from that Node. If you need to be specific, you can use jQuerys Event namespacing, like so
$('.example').on( 'mouseenter.myNamespace'
function () {
$(this).css('background','red');
}
).on('mouseleave.myNamespace'
function() {
$(this).css('background','yellow');
}
);
and use this call to only unbind any event that is within the namespace .myNamespace
$(this).css('marginTop','+=20px').removeClass('example').off('.myNamespace');
$('.example').unbind('mouseenter').unbind('mouseleave')
In your code, $('.example').hover attaches a mouseenter and mouseleave directly to each element.
-or-
A better solution might be to use delegation with on
$(document.body).on('mouseenter', '.example', function() { ... });
$(document.body).on('mouseleave', '.example', function() { ... });
Using that code, removing the example class will work as expected, because the handlers are based on css selector, while .hover attaches directly to the elements.
$('.example').live({
mouseenter:function () {
$(this).css('background','red');
},
mouseleave:function () {
$(this).css('background','yellow');
}
});
demo: http://jsfiddle.net/gSfc3/1/
Try this:
$('.test').hover(
function () {
$('.example').css('background','red');
},
function () {
$('.example').css('background','yellow');
}
);

How do I add a click handler to a class and find out which element was clicked?

I have been using the following method for adding a click event to an id, I was wondering if I could do the same with a class.... I have a number of items (which are created in a for each loop) and I need to be able to click them and then pickup which was clicked... here is my existing code
$('submit-button').bind('click', submit_click);
function submit_click() {
alert('I am clicked');
}
I was wondering if there is some way to pass in a variable into my function for the click so i can check the ID?? or similar
hence this
function submit_click(element) { // notice element
alert(element + ' clicked');
}
Any help really appreciated
Thank you
EDIT
I have tried the following and in debug "elem" is undefined...
$('.clear').bind('click', clear_click($(this)));
function clear_click(elem)
{
alert(elem.attr("id"));
}
WORKING SOLUTION
I have the working solution but I don't fully understand why, I would love to know why it works..
First of all I tried
$('.clear').bind('click', clear_click($(this)) );
This seemed to work "BUT" when I loaded the page it enter the "clear_click" method without being clicked - strange...
Then I tried this..
$('.clear').bind('click', function() { clear_click($(this)) } );
This works great! But I don't understand why I must pass a function and then within this function call my clear_click.
Can anyone explain why 1 works and the other doesn't?
Whenever I need to call a callback function or similar I should first open a function() and then call the method inside the function?
$(".yourclass").click ( function() {
$(this).attr ( "id" ); //S(this) returns the current element
});
and you can code like this
$('.yourclass').bind('click', function() { submit_click($(this)) });
function submit_click(elem)
{
alert ( elem.attr ("id" ) );
}
Edit
$('.clear').bind('click', function() { clear_click($(this)) });
function clear_click(elem)
{
alert(elem.attr("id"));
}
This will work fine for you.
Update
To answer your second question:
You can bind a function as a second argument when using the click event, but you cant bind a function and apply arguments. On the other hand, there is no need to send this as an argument to the clear_click function since the this keyword inside the function refers to the element itself:
So this works in your case:
$('.clear').bind('click', clear_click);
function clear_click() {
alert(this.id);
}
Sending this as an argument is not needed and bad coding:
$('.clear').bind('click', clear_click(this));
In the event handler, the first argument is the event object. You can extract the clicked element from that object using currentTarget or target. In jQuery, this always refers to the currentTarget in the event handler context:
var handler = function(e) {
var id = this.id; // this == e.currentTarget
}
$('submit').click(handler); // .click(fn) is shorthand for .bind('click', fn)
More examples:
$('submit').bind('click', function(e) {
console.log(e.target) // the target that was clicked on
console.log(e.currentTarget) // the element that triggered the click
console.log(this) // the same as above
});
Just add $(this) to your function, You don't need to send any parameters because you are still in the context of the clicked element.
function submit_click() { // notice element
alert($(this).attr('id') + ' clicked');
}
When you bind a handler to a function, the clicked element will be the first argument
$('.submit-button').click(submit_click);
function submit_click(element){
//element is the .submit-buttom element
alert(element+' was clicked');
alert($(element)+' was clicked');
}
This should work:
$('.submit-button').bind('click', submit_click($(this)));
function submit_click(element) { // notice element
alert($(element).attr("id") + ' clicked');
}

Categories

Resources