I have a click event which fires when I click on a button, it opens a modal interface:
$(".profileF2fClinicalServiceDetails").live("click", function(){
var requestUrl = '/php/includes/ajax.php?operation=profile_edit_f2f_clinical_service_details&service=f2f&counsellor_id='+getPractitionerId($(this))+'&counsellor_address_id='+getAddressId($(this))+'&edit_level='+getEditLevel($(this))+'&tab='+getTab($(this));
openDialog(requestUrl, "Edit Face to Face Service Details", 850, "location.replace(getCleanedLocationHref()+'&tab="+getTab($(this))+"');");
return false;
});
But now I want to prompt this to be fired when a page loads, how do I call it directly from the HTML?
Add the code in the click event to an independent function (rather than a closure) called, for example, showPopup. Then change the function bound to the click event to call showPopup, and add a call to showPopup function on page load.
A note, as of 1.7 jQuery's live function is deprecated, you should use on instead (source)
You will have to pass some arguments to the function, since you won't be able to use this during the initial call. You will have to pass those arguments to the main function the first time you call it, I won't presume to guess how you'll determine that.
When the click event is fired, you can extract the arguments from the element in the fashion you're currently using. You'd have something like this:
$(document).ready(function() {
// add the click event
$(".profileF2fClinicalServiceDetails").on("click", function () {
var Me = $(this);
showPopup(
getPractitionerId(Me),
getAddressId(Me),
getEditLevel(Me),
getTab(Me)
);
});
// call the function right away
showPopup(
[initial_counsellor_id],
[initial_address_id],
[initial_level],
[initial_tab]
);
});
function showPopup(counsellor_id, address_id, level, tab) {
var requestUrl = '/php/includes/ajax.php?operation=profile_edit_f2f_clinical_service_details&service=f2f&counsellor_id='+counsellor_id+'&counsellor_address_id='+address_id+'&edit_level='+level+'&tab='+tab;
openDialog(
requestUrl,
"Edit Face to Face Service Details",
850,
"location.replace(getCleanedLocationHref()+'&tab="+tab+"');"
);
return false;
}
Documentation and Related Reading
jQuery.ready - http://api.jquery.com/ready/
jQuery.on - http://api.jquery.com/on/
jQuery.live - http://api.jquery.com/live/ [DEPRECATED]
Javascript functions on MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Functions
Related
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.
<li>KONKURRANSEREGLER</li>
<div class ="contactButton"> <span>Kontakta Oss</span></div>
These two buttons don't work as links, see: http://www.undergroundblc.co.uk/chaqwa/ i.e. you click but nothing happens. If you change 'return false' to 'return true' the buttons work again but no longer register with the tracking company. So my question is how do I keep 'return false' yet get them to work as links.
First of all. If you HAVE to have javascript embedded in your html (not recommended) you don't need to have the javascript: declaration in events (onclick in your example). It would be much better to use dom methods el.addEventListener('click', kenshoo_conv, false).
If you need to fire a function before the page unloads you will need some control of that function to know when it has successfully fired the tracking becon.
Once you have your onclick attached, you can use the event argument (that is passed to the function) to stop the event from firing, evt.preventDefault(), do everything you need to do, then set the location.href when your tracker becon has successfully fired.
All up your code could look something like this (assuming everything is normalised, so not in IE):
HTML
<a href="konkurranseregler.html" data-args="rules,0,,sem,NOK"
class="kenshoo_conv_link">KONKURRANSEREGLER</a>
JAVSCRIPT
function kenshoo_conv(evt) {
var dest = this.href,
args = this.getAttribute('data-args').split(",");
evt.preventDefault();
//add success event to arguments
args.push(function () {
location.href = dest;
});
//fire the tracking function
trackMe.apply(this, args);
}
var kenshoo_conv_links = document.getElementsByClassName("kenshoo_conv_link");
for (var i = 0, il = kenshoo_conv_links.length; i < il; i += 1) {
kenshoo_conv_links[i].addEventListener('click', kenshoo_conv, false);
}
This will make the last argument in the trackMe function a callback to change the location to the destination of the link. So you'll have to fire that function once the tracker has successfully fired. If you don't know that, you could do it after a timeout (not ideal)
I have two parts of scripts.
Part 1 :
$("mySelector").click(function() {
alert('you call me');
})
Part 2 :
$("mySelector").click(function() {
if(myCondition) {
//how can i prevent calling the first function from here ???
}
})
The whole problem, is that i have no access to part1. So i need to unbind the event allready specified in part 1, if myCondition is true, but otherwise i need to call the first function.
Thanks
UPDATE:
Thank you. I didn't know about stopImmediatePropagation(). But i feel, that there must be something like that :)
But actually in my case it doesn't work :(
Please have a look at my site
http://www.tours.am/en/outgoing/tours/%D5%80%D5%B6%D5%A4%D5%AF%D5%A1%D5%BD%D5%BF%D5%A1%D5%B6/Park-Hyatt-Goa/
Under the hotel description tab i have cloud carousel, when i click on not active image (not the front image), as you can see i'm consoling that i stopImmediatePropagation() there, but the event however calls :(
If your handler is registered first, then you can use event.stopImmediatePropagation like this:
$("mySelector").click(function(event) {
if(myCondition) {
event.stopImmediatePropagation();
}
})
Be aware that this will also stop event bubbling, so it will also prevent click handlers on parent elements from being invoked.
Update: If this does not work, then your handler is attached after the one you want to control. This is a problem that makes the solution much more difficult. I suggest seeing if you can bind "before the other guy", otherwise you will have to unbind the existing handler and then conditionally invoke it from within your own by retaining a reference to it. See jQuery find events handlers registered with an object.
No access:
$("#mySelector").click(function() {
alert('you call me');
})
Access:
var myCondition = true, //try false too
fFirstFunction = $("#mySelector").data("events").click[0].handler;
$("#mySelector").unbind("click");
$("#mySelector").click(function() {
if(myCondition) {
alert(myCondition);
} else {
$("#mySelector").click(fFirstFunction);
}
});
Look at this example
You can call
$('mySelector').unbind('click');
to get rid of all the click handlers. If your script is loaded after the other one (which appears to be the case), then that should do it. However note that it does unbind all "click" handlers, so make sure you call that before you add your own handler.
If you can't ensure your handler is attached first, try the following code:
var events = $('mySelector').data("events"); //all handlers bound to the element
var clickEvents = events ? events.click : null;//all click handlers bound to the element
$('mySelector').unbind('click'); //unbind all click handlers
//bind your handler
$("mySelector").click(function(e) {
if (myCondition) {
//do what you want
} else {
//call other handlers
if (clickEvents) {
for (var prop in clickEvents)
clickEvents[prop].call(this, e);
}
}
})
Update:
Above code is for jQuery 1.3.2
Above code is based on internal implementation of jQuery 1.3.2, so please check it carefully once you update jQuery.
return false;
-or-
event.preventDefault();
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)
So im trying do disable links on some <li> ellements that have been loaded in from another page using an .load() function, but for some reason i'm not able to effect those list items.
var from_post = false;
$(document).ready(function() {
//so this is the function that loads in data from another page
$("#gallery").load('http://localhost/index.php/site/gallerys_avalible/ #gallerys_avalible'), function() {
console.log('hello');
// sense there are no other li elliments on the page i thought this
// would be okay. but this function never gets called, i've moved it
// all over i just recently attached it to the load function thinking
// that maybe if the load was not complete it would not run, but i
// have had no luck.
$('li').click(function (e) {
e.preventDefault();
console.log("I have been clicked!");
return false;
});
};
$('#addNew').click(function () {
console.log('i got called');
$('#new_form').fadeIn(1000);
});
$('form').submit(function() {
if(from_post) {
//submit form
return true;
} else {
//dont submit form.
return false;
}
});
any help would be greatly appreciated, oh and the other thing is that i can run this function through firebug, and it works 100% fine. so im stumped.
You are closing your call to .load() too early. You have:
$("#gallery").load('http://...'), function() {
That just calls load and then declares a function. But, that function is not bound to the success handler and it will never be executed. You need the ) to be on the other side of the function declaration so that the function is included as a parameter to your call to load:
$("#gallery").load('http://...', function() {
...
});
Fix that and your code works: http://jsfiddle.net/gilly3/WdqDY/
Try a future-proof event observer like live or delegate:
$('li').live('click', function(){})
or, this method is preferred if you know the parent:
$('#gallery').delegate('li','click',function(){})
The reason for needing this is your click events are being bound to elements that are on the page at the time of the binding. Any li's added later will not see that binding which is how live or delegate works. They bind to the parent and traverse the child nodes every (click in this case) event to see if the event applies to an existing child.
Use .live('click', ...) or .delegate() instead of .click(...).