JavaScript/jQuery - Reusing the event 'Click' of an element - javascript

I have an element, a div, for example. And attach an event 'click' to it. In jQuery, it would be:
$('#myDiv').click(function(){
$(".class1").show();
})
Now, I would like to assign a new function "myDiv #", replacing the old. I am doing so:
$('#myDiv').click(function(){
$(".class23").hide();
})
But when I run the 'click' on the div, the function I assigns the beginning of this doubt is performed.
Question: How to remove the function that will run with the click event attributed to an element? (No recreate the element with the new click event...)

You want .unbind.
You can either remove all previous bound functions:
$('#myDiv').unbind('click');
Or if you only want to unbind one specific function:
var show = function() {
$(".class1").show();
};
$('#myDiv').click(show);
and then:
$('#myDiv').unbind('click', show); // unbind first function
$('#myDiv').click(function() { // bind second function
$(".class23").hide();
});
Note that .click(func) is just a shortcut to .bind('click', func).

If you know you'll only want to handle one click on an element, you can use one() which automatically unbinds after a single click:
$("#myDiv").one("click", function() {
$(".class1").show();
$("#myDiv").one("click", function(){
$(".class23").hide();
});
});

Use the JQuery unbind function to remove all click events
$('#myDiv').unbind('click');

Add a counter on the first click event.
var counter = 0;
$('#myDiv').click(function(){
if(counter>1){
$(".class23").hide();
}
else
$(".class1").show();
counter++;
})
just an example..

Related

How to prevent jQuery duplicate function being called

I have a jQuery on('click') function like this:
function enabled_click() {
$('.btn_enabled').on('click', function() {
alert('CLICKED');
});
}
and then I have another post function like this
$(document).on('click', '.btn_add_link', function(e) {
var url = 'www.xxx.my-function';
post_data(url, function(data) {
if (data.status == 'success') {
$('#my_wrapper').append(data.response);
enabled_click();
} else {
alert('error');
}
});
return false;
});
The post function will append another .btn_enabled button. If i did not call the enabled_click() function on the success post, then the newly added .btn_enabled would not be able to trigger the onclick function.
But if I call the enabled_click() function like i did above, the already existing .btn_enable will then call the onclick function twice and alert CLICKED twice. Is there any way to make it so it only alerts once?
Event delegation by binding to a common parent, as answered by #qs1210, is a possible solution, and a very efficient one (because there's only one common handler instead of one per element). But depending on the code, it may require more changes.
As a compatible "drop-in replacment" just unbind the event handler before binding again. To achieve this in an easy and stable way, you can use jQuery's "namespace" feature for event names (see .on(), "Event names and namespaces"):
function enabled_click(){
$( '.btn_enabled' )
.off('click.some_namespace')
.on('click.some_namespace'), function() {
alert('CLICKED');
});
}
Note: if you extract the event handler into its own function and use that as second parameter to .off(), you could omit the namespace:
function click_handler(){
alert('CLICKED');
}
function enabled_click(){
$( '.btn_enabled' )
.off('click', click_handler)
.on('click', click_handler);
}
But this only works it the click_handler variable is "stable": depending where and when the click handler is defined, the variable (click_handler in this example) could be re-assigned and .off() couldn't detach the previous handler anymore.
Follow-up: in your example, you only apply the event handler to newly appended elements ($('#my_wrapper').append(data.response)). You could alter enabled_click to explicitly take the new element(s) as an argument:
function enabled_click($element){
$element.find('.btn_enabled' ).on('click', function() {
alert('CLICKED');
});
}
and call it like this:
var $newElement = $(data.response);
$('#my_wrapper').append($newElement);
enabled_click($newElement);
Now the event handler gets attached to new elements only, and not to already existing which have the event handler already attached.
(I'm using $ as prefix for all my variables holding jQuery collections, in order to distinguish them from pure DOM nodes)
Your can write like this
document.on('click', '.btn_enabled', function() {
alert('CLICKED');
})`
delegate event to dom, it makes everything harmony.

jQuery override an on() event with another on() event

I have 2 files, file 1 (head.tpl) contains this default function operation
$(document).on("click", "#blackout", function(){
closeSkyBox();
});
That is the default operation I want to run, and it works.
On my second page, I would like to override the operation that is in head.tpl with this:
$(document).on("click", "#blackout", function(){
closeSkyBox(function(){
pev_for_country = '';
});
});
So, now when I test the code, each one runs, so If I were to place an alert (for testing reasons) I get two alert boxes. How can I make it so only the one in the second page runs, and the one in head.tpl is disabled. Then when I don't override it say on a third page, the one in head.tpl runs?
Looks like you're looking for jQuery's .off
$(document)
.off('click', '#blackout')
.on('click', '#blackout', function () {
// ...
});
You can use .off to remove all event handlers, but you should be cautious: what if other libraries add event handlers that you don't want to remove subscribe to this event? Also, if you add an additional event handler at a later date, this would obliterate it.
A better approach, I think, is to create a function that you can override:
function blackoutClick() {
closeSkyBox();
}
And set up your click handler:
$(document).on("click", "#blackout", function(){
blackoutClick();
});
Or, as Paul pointed out in the comments below, you don't even need to wrap that handler in an anonymous function, you can just use the cleaner:
$(document).on("click", "#blackout", blackoutClick );
Then, in your second page, you can just modify that function:
function blackoutClick() {
closeSkyBox(function(){
pev_for_country = '';
});
I believe another way to do it is also to set the event to null...
$(document).on('click', '#blackout', null);
before you re-set it on your second page.

click outside DIV

<body>
<div id="aaa">
<div id="bbb">
</div>
</div>
</body>
$(#?????).click(function(){
$('#bbb').hide();
})
http://jsfiddle.net/GkRY2/
What i must use if i want hide #bbb if user click outside box #bbb? But if i click on div #bbb then box is still visible - only outside.
$('body').click(function(e){
if( e.target.id == 'bbb' )
{ return true; }
else
{ $('#bbb').hide(); }
});
A note of explanation: There are a few ways to do this, either way we need to listen for a click on a parent element, weather it be a direct parent like #aaa or a distant parent like the body or the document. This way we can capture clicks that occur outside of #bbb.
Now that we have that we need the .hide to NOT occur if the user did click inside of #bbb. We can do this two ways
Stop propagation if the user clicks on #bbb. This will make the click event not 'bubble' up to the parent. That way the click event never reaches the parent and so #bbb will not hide. I personally don't like this method because stop propagation will so ALL click events from bubbling, and you may have click events that you would like to bubble to a local parent and not a distant parent. Or you may have listeners delegated from a distant parent, which will stop working if click propagation is stopped.
Check for the #bbb element in the parent listener. This is the method shown above. Basically this listens on a distant parent, and when a click occurs it checks to see if that click is on #bbb specifically. If it IS NOT on #bbb .hide is fired, otherwise it returns true, so other things that may be tied into the click event will continue working. I prefer this method for that reason alone, but secondarily its a-little bit more readable and understandable.
Finally the manner in which you check to see if the click originated at #bbb you have many options. Any will work, the pattern is the real meat of this thing.
http://jsfiddle.net/tpBq4/ //Modded from #Raminson who's answer is very similar.
New suggestion, leverage event bubbling without jQuery.
var isOutSide = true
bbb = documment.getElementById('bbb');
document.body.addEventListener('click', function(){
if(!isOutSide){
bbb.style.display = 'none';
}
isOutSide = true;
});
bbb.addEventListener('click', function(){
isOutSide = false;
});
Catch the click event as it bubbles-up to the document element. When it hits the document element, hide the element. Then in a click event handler for the element, stop the propagation of the event so it doesn't reach the document element:
$(function () {
$(document).on('click', function () {
$('#bbb').hide();
});
$('#bbb').on('click', function (event) {
event.stopPropagation();
});
});
Here is a demo: http://jsfiddle.net/KVXNL/
Docs for event.stopPropagation(): http://api.jquery.com/event.stopPropagation/
I made a plugin that does this. It preserves the value for this where as these other solutions' this value will refer to document.
https://github.com/tylercrompton/clickOut
Use:
$('#bbb').clickOut(function () {
$(this).hide();
});
You can use target property of the event object, try the following:
$(document).click(function(e) {
if (e.target.id != 'bbb') {
$('#bbb').hide();
}
})
DEMO
This will work
$("#aaa").click(function(){
$('#bbb').hide();
});
$("#bbb").click(function(event){
event.stopPropagation();
})​
Becouse bbb is inside the aaa the event will "bubbel up to aaa". So you have to stop the bubbling by using the event.stopPropagation when bbb is clicked
http://jsfiddle.net/GkRY2/5/
OK
* this is none jquery. you can easly modify it to work with IE
first create helper method to facilitate codding don't get confused with JQuery $()
function $g(element) {
return document.getElementById(element);
}
create our listener class
function globalClickEventListener(obj){
this.fire = function(event){
obj.onOutSideClick(event);
}
}
let's say we need to capture every click on document body
so we need to create listeners array and initialize our work. This method will be called on load
function initialize(){
// $g('body') will return reference to our document body. parameter 'body' is the id of our document body
$g('body').globalClickEventListeners = new Array();
$g('body').addGlobalClickEventListener = function (listener)
{
$g('body').globalClickEventListeners.push(listener);
}
// capture onclick event on document body and inform all listeners
$g('body').onclick = function(event) {
for(var i =0;i < $g('body').globalClickEventListeners.length; i++){
$g('body').globalClickEventListeners[i].fire(event);
}
}
}
after initialization we create event listener and pass reference of the object that needs to know every clcik on our document
function goListening(){
var icanSeeEveryClick = $g('myid');
var lsnr = new globalClickEventListener(icanSeeEveryClick);
// add our listener to listeners array
$g('body').addGlobalClickEventListener(lsnr);
// add event handling method to div
icanSeeEveryClick.onOutSideClick = function (event){
alert('Element with id : ' + event.target.id + ' has been clicked');
}
}
* Take into account the document body height and width
* Remove event listeners when you don't need them
$(document).click(function(event) {
if(!$(event.target).closest('#elementId').length) {
if($('#elementId').is(":visible")) {
$('#elementId').hide('fast');
}
}
})
Change the "#elementId" with your div.

jQuery: Get reference to click event and trigger it later?

I want to wrap an existing click event in some extra code.
Basically I have a multi part form in an accordion and I want to trigger validation on the accordion header click. The accordion code is used elsewhere and I don't want to change it.
Here's what I've tried:
//Take the click events off the accordion elements and wrap them to trigger validation
$('.accordion h1').each(function (index, value) {
var currentAccordion = $(value);
//Get reference to original click
var originalClick = currentAccordion.click;
//unbind original click
currentAccordion.unbind('click');
//bind new event
currentAccordion.click(function () {
//Trigger validation
if ($('#aspnetForm').valid()) {
current = parseInt($(this).next().find('.calculate-step').attr('data-step'));
//Call original click.
originalClick();
}
});
});
jQuery throws an error because it's trying to do this.trigger inside the originalClick function and I don't think this is what jQuery expects it to be.
EDIT: Updated code. This works but it is a bit ugly!
//Take the click events off the accordion elements and wrap them to trigger validation
$('.accordion h1').each(function (index, value) {
var currentAccordion = $(value);
var originalClick = currentAccordion.data("events")['click'][0].handler;
currentAccordion.unbind('click');
currentAccordion.click(function (e) {
if ($('#aspnetForm').valid()) {
current = parseInt($(this).next().find('.calculate-step').attr('data-step'));
$.proxy(originalClick, currentAccordion)(e);
}
});
});
I think this:
var originalClick = currentAccordion.click;
Isn't actually doing what you think it is - you're capturing a reference to the jQuery click function, rather than event handler you added, so when you call originalClick() it's equivalent to: $(value).click()
I finally came up with something reliable:
$(".remove").each(function(){
// get all our click events and store them
var x = $._data($(this)[0], "events");
var y = {}
for(i in x.click)
{
if(x.click[i].handler)
{
y[i] = x.click[i].handler;
}
}
// stop our click event from running
$(this).off("click")
// re-add our click event with a confirmation
$(this).click(function(){
if(confirm("Are you sure?"))
{
// if they click yes, run click events!
for(i in y)
{
y[i]()
}
return true;
}
// if they click cancel, return false
return false;
})
})
This may seem a bit weird (why do we store the click events in the variable "y"?)
Originally I tried to run the handlers in x.click, but they seem to be destroyed when we call .off("click"). Creating a copy of the handlers in a separate variable "y" worked. Sorry I don't have an in depth explanation, but I believe the .off("click") method removes the click event from our document, along with the handlers.
http://www.frankforte.ca/blog/32/unbind-a-click-event-store-it-and-re-add-the-event-later-with-jquery/
I'm not a jQuery user, but in Javascript, you can set the context of the this keyword.
In jQuery, you use the $.proxy() method to do this.
$.proxy(originalClick, value);
originalClick();
Personally, I'd look at creating callback hooks in your Accordion, or making use of existing callbacks (if they exist) that trigger when opening or closing an accordion pane.
Hope that helps :)
currentAccordion.click is a jQuery function, not the actual event.
Starting with a brute-force approach, what you'd need to do is:
Save references to all the currently bound handlers
Unbind them
Add your own handler, and fire the saved ones when needed
Make sure new handlers bound to click are catched too
This looks like a job for an event filter plugin, but I couldn't find one. If the last point is not required in your application, then it's a bit simpler.
Edit: After some research, the bindIf function shown here looks to be what you'd need (or at least give a general direction)

Adding a function to onclick event by Javascript!

Is it possible to add a onclick event to any button by jquery or something like we add class?
function onload()
{
//add a something() function to button by id
}
Calling your function something binding the click event on the element with a ID
$('#id').click(function(e) {
something();
});
$('#id').click(something);
$('#id').bind("click", function(e) { something(); });
Live has a slightly difference, it will bind the event for any elements added, but since you are using the ID it probably wont happen, unless you remove the element from the DOM and add back later on (with the same ID).
$('#id').live("click", function(e) { something(); });
Not sure if this one works in any case, it adds the attribute onclick on your element: (I never use it)
$('#id').attr("onclick", "something()");
Documentation
Click
Bind
Live
Attr
Yes. You could write it like this:
$(document).ready(function() {
$(".button").click(function(){
// do something when clicked
});
});
$('#id').click(function() {
// do stuff
});
Yes. Something like the following should work.
$('#button_id').click(function() {
// do stuff
});

Categories

Resources