(Why) does jQuery .click() require a callback function? - javascript

I have the following jQuery code:
function next() {
//some code here
}
function previous() {
//some code here
}
$("#next").click(function(){
next();
});
$("#previous").click(function(){
previous();
});
This works, but this doesn't:
$("#next").click(next());
$("#previous").click(previous());
Why is this happening? Is there a problem in my code, or is this just a thing with jQuery? Note: #next and #previous refer to two buttons in my html file.

The callback should be a reference to the function.
Why $("#next").click(next()); doesn't work?
func() is a function call and not a reference, which is why it is called immediately.
This,
$("#next").click(function(){
next();
});
is a preferable way in case you need to pass arguments.
Else,
$("#next").click(next) //notice just the signature without ()

This works (if the functions next and previous are defined):
$("#next").click(next);
$("#previous").click(previous);
In this case the next and previous are also callback functions, the difference between the two is,
when you call this line
$("#next").click(next()); the function is executed immediately, and you are passing the result of the next function to the eventHandler of jQuery.
and in this case
$("#next").click(next); you are passing the function next to the EventHandler of jQuery.
Btw.: in the jQuery API Documentation (https://api.jquery.com/click/) it shows all parameters for the click function and the required types it states: "...handler Type: Function( Event eventObject ) A function to execute each time the event is triggered. ..."

try like this you will get your answer,
function next() {
//some code here
}
function previous() {
//some code here
}
$("#next").click(next);
$("#previous").click(previous);
working demo jsfiddle Example

What is going on there is a little bit obscured by the syntax of anonymous functions function() { ... }. What you are doing by that is passing a function, without calling it. And I want to explain how this works:
If you have a simple function
function next() { return 5 };
It will simply return the value 5, if you call it from somewhere:
a = next(); // value of a will be 5
But what you can do too, is to pass the whole function to a. This is possible, because functions in JavaScript are actually objects:
a = next;
b = a(); // value of b will be 5
If you look at the syntax, it shows you, that putting parentheses () at the end of a function invokes it, and returns the return value. While the naked string, without parentheses hands you the function itself.
So what is a callback now, and what does click() like to get as a parameter? A callback function is a function, that gets called later; we actually hand it over, to get called later. click() would like to get such a function as parameter, and it should be clear now, that we have to pass the function without parentheses, to enable click() to call it later, instead of just passing a 5 to it.
$("#next").click(next);
So how does then the initial syntax with the anonymous function work?
function() { next(); }
actually wraps your next() into another function, which is anonymous – because it does not have a name – but is working in the same way as a named function. You can even set a variable by it:
a = function() { next(); } // a will be the anonymous function that calls next()
But calling that function a() will return nothing, because the anonymous function does not return a value (To be exactly: every function call in JavaScript is returning at least undefined, but that's a technical detail).
It can even be called immediately by putting parenthesis at the end of it:
a = function() { return next(); }() // value of a will be 5
Adding the return there will make sure, the return value of next() will be passed through the anonymous function.
This should make clear why
$("#next").click(function(){ next(); });
is working, and why
$("#next").click(next());
is not, but
$("#next").click(next);
will be a good solution.

$("#next").click(next); would work. Notice parenthesis are not required as the function/callback handler should be passed as a parameter.

Related

How to run an anonymous function that was given as parameter

I know i can have a function as a parameter in javascript. I can also run that function that was given as a parameter. Here's an example:
function myfunction(param1, callbackfunction)
{
//do processing here
callbackfunction();
}
What if i wanna give an anonymous function, how will this run inside the outer function.
For example with a function like
setTimeout(function(){
})
How is this anonymous function directly run without a name?
You don't need a name to call a function. Names are only useful for use in a debugging tool (e.g. when examining a stack trace).
To call a function you need an expression that resolves as the function, which you can follow with ().
You're passing the function as the first argument to setTimeout, so it gets stored in the first parameter of that function. setTimeout's internals then call it.
You do the same with your code, only it is the second argument.
myfunction("some param", function () { /* ... */ }) ;
Maybe this makes it clearer?
function callFunction(param1, callbackfunction) {
console.log('callFunction', param1)
//do processing here
callbackfunction(param1);
}
function myCustomCallback(param) {
console.log('myCustomCallback', param)
}
setTimeout(callFunction.bind(this, 'one', myCustomCallback ), 1000)
setTimeout(callFunction.bind(this, 'two', function(p) {alert(p)} ), 2000)

Passing anonymous functions through jQuery event call without eventData

Given an <input id="foo"> element, I want to call an existing function on blur and pass an anonymous callback to it.
Case 1, simple function call:
function bar(){
alert("I am");
}
$("#foo").blur(bar); //Works fine
Case 2, passing arguments/function:
$("#foo").bind("blur", {func: function(){console.log("I am apple")}}, bar);
function bar(event){
event.data.func(); //Works fine
};
Problem with case 2 is that I'd like to have bar() as a generic function called by more than blur, in which case I would be passing anonymous function directly, not "baked" into a data object. So ideally like this:
function bar(callback){
//Do stuff
callback();
}
bar(function(){console.log("Hello Earth")}); //Works
$("#foo").blur(bar(function(){console.log("Hello world")})); //Doesn't work
Last line doesn't work as function gets executed directly, but it's an example of what I would like to achieve. I guess I possibly could make some typeof checks in bar() to determine what I am receiving, but I wanted to ask if there's a cleaner way to pass anonymous function on blur, instead of changing bar().
...I wanted to ask if there's a cleaner way to pass anonymous function on blur, instead of changing bar().
Not sure quite what you mean by that, you will have to either change bar or wrap bar.
Changing it:
Make bar a handler generator rather than a direct handler:
function bar(callback) {
return function(e) {
// You could use `e` (the event) here and/or pass it on to the callback
callback();
// You might use the callback's return, e.g.:
// return callback();
// ...if you wanted it to be able to `return false`
};
}
Now, bar returns an event handler that will call the callback (in addition, presumably, to doing something of its own; otherwise, it's a bit pointless and you'd just pass the callback directly).
Usage:
$("#foo").blur(bar(function(){console.log("Hello world")}));
Wrapping it
If you literally mean you don't want to change bar, you'll need to wrap it:
function wrap(f, callback) {
return function() {
// You could call `callback` here instead of later if you like
// Call the original function passing along the `this` and
// arguments we received (`arguments` isn't pseudo-code, it's
// a pseudo-array JavaScript creates for you), get its return value
var retval = f.apply(this, arguments);
// Call the callback
callback();
// Return the original function's return value
return retval;
};
}
If you want to avoid letting errors thrown by callback to make it to the event mechanism, you can wrap it in a try/catch.
Usage:
$("#foo").blur(wrap(bar, function(){console.log("Hello world")}));
function bar(callback){
//Do stuff
callback();
}
bar(function(){console.log("Hello Earth")}); //Works
$("#foo").blur(bar.bind(this,function(){console.log("Hello world")})); //Will work
Wrap it and return it as an anonymous function:
function bar(callback){
return function() {
callback();
}
}
// direct
bar(function(){console.log("Hello Earth")})();
// as callback
$("#foo").blur(bar(function(){console.log("Hello world")}));
function bar(){
alert("I am blur");
}
$("#foo").bind('blur',bar);
Last line doesn't work as function gets executed directly
$("#foo").blur(bar(function(){console.log("Hello world")}));
On the last line you're passing the result of bar to the blur() function, not bar itself, it's the same as:
var result = bar(function(){console.log("Hello world")});
$("#foo").blur(result);
The standard method is to wrap this in an anon function:
$("#foo").blur(function() { bar(function(){console.log("Hello world")}) });
This means there are no changes to your other existing functions, as per the question requirement: "instead of changing bar()"

Is this a correct way of JavaScript/jQuery callback?

This is a simple question. Here is my code:
$(document).ready( function () {
func1( "foo", callback);
function callback(param){
alert(param+" is my name");
}
function func1(name, cb) {
cb(name); // alerts "foo is my name"
callback("bar"); // alerts "bar is my name"
}
});
I want to know:
Which one of the function calls inside func1 is the correct callback and why?
Or are they both correct?
Isn't callback("bar"); a normal function call?
Callbacks are meant to let a caller specify what a function should do at some defined point in that function's execution. The function being called shouldn't know the name of that callback function ahead of time. So they'll often be passed to a function as an argument and the function that's supposed to call the callback should just invoke that argument.
When you call callback("bar") in func1, you're totally missing the point of callbacks. You may be invoking the function that you happen to use as a callback, but the point of callbacks is that func1 isn't supposed to know about that. It's just supposed to call the function that's been passed in as an argument (cb). When I'm calling func1 I should be able to pass a completely different callback function and func1 should just call that function without knowing what its name is (it may not even have one!).
The "correct" way is cb(name).
callback("bar"); is directly invoking the callback function where as cb(name); calls the reference passed to the func1,
cb(name); seems to be the correct way here.
First one. Function calls another one which has been pased as a parameter.
It seems like most jquery methods follow this this form for callbacks:
$(SUBJECT).method(function() {
//do stuff
}, /*callback here*/ function(){
//do stuff
});
like for instance
$(foo).click(function() {
$(bar).fadeIn(300, function(){
//call back here
});
});
fiddle

jQuery - Using anonymous function passed in as function parameter as jQuery callback function

This is best explained by a code example, so can anyone explain why (in technical terms) the anonymous function passed to test doesn't get called after the jQuery hide event?
UPDATE: Not that is really matters for this example what this is referring to, but for clarity lets say test function is in the global scope and this is an anchor element.
test(this, function() {
alert('Called by anonymous function!');
});
function test(object, callback) {
$(object).hide('slow', callback);
}
Changing:
$(object).hide('slow', callback);
To:
$(object).hide('slow', callback());
works. Is this because callback isn't a named function in the current context or global window object?
Your code should look more like this
test(this, function() {...});
You're not calling an anonymous function in your code, but I'm not sure what that syntax actually does
Check out this fiddle of a working example http://jsfiddle.net/L4NxD/2
Edit, made more edits to the fiddle to better duplicate original code. Use http://jsfiddle.net/L4NxD/1 and just http://jsfiddle.net/L4NxD/ to get earlier versions.
This is the correct way to do it.
http://jsfiddle.net/6dFm6/6/
Calling remove after the hide animation will remove the object and result in the animation callback not being called.
The reason it works in jsfiddle.net/6dFm6/1 is because the callback is executed at runtime and the value is passed and called during the callback event.
See these articles for varying level of clarity on what is returned by 'functionName()' as the callback. It appears 'undefined' is returned by the call, however the execution still happens at the correct time.
When to use () after a callback function name?
In JavaScript, does it make a difference if I call a function with parentheses?
Callback function - use of parentheses
do I need parenthesis when using a named function as an jquery ajax success callback
javascript syntax: function calls and using parenthesis

Javascript callback function scope?

I have a javascript function that has a callback then an anonymous function then another callback, and something has gone wrong with the scope. The parameter callbackFunc is retaining its value from the first function call and not using the new value passed in the 2nd function call.
function IsReady(callbackFunc) {
if (!IsValid()) return false;
IsConnected(function () {
if (typeof (callbackFunc) == 'function')
callbackFunc();
return true;
});
}
function IsConnected(validCallbackFunc) {
$.post("IsConnected", function (data) {
if (data.IsValid) {
if (validCallbackFunc && typeof (validCallbackFunc) == 'function')
validCallbackFunc();
}
});
}
$('#SaveButton').click(function () {
IsReady(SaveInvoice); // works
});
$('#ExportButton').click(function () {
// works only if IsConnected() is true
// otherwise SaveInvoice is called again
IsReady(ExportInvoice);
});
function SaveInvoice() {}
function ExportInvoice() {}
In some circumstances, when I click the ExportButton, the SaveInvoice function is run instead of the ExportInvoice function. I'm guessing that it's a scoping issue - that somehow the old value of callbackFunc has been retained. But I don't quite understand it due to the mix of callback + anonymous function + another callback. I didn't write this code, but I have to fix it. Is there anything I can do to clear the value of callbackFunc at the end of IsReady()?
IsReady(ExportInvoice) works if IsConnected() is true. If IsConnected() is false then the result is that SaveInvoice() gets executed when in fact nothing should happen (because it is not connected).
There is no way that the callbackFunc value could be retained between two different calls of the IsReady function.
In your code, each time a click event handler is executed, a new scope is created when IsReady is called. Each scope has it's own local parameter callbackFunc. Each scope will define its own anonymous function passed to IsConnected where resides the callbackFunc variable enclosed in a closure.
So this is not a scope problem.
To prove it, I emulated your code here: http://jsfiddle.net/pwJC7/
In your code you talk about the IsConnected return value. This function actually does not return anything. The connection status seems to be checked through an ajax call returning an XML or JSON data with an IsValid property (emulated by $_post in the fiddle).
Maybe your issue is due to this asynchronous call. But it's impossible that you experience a call to SaveInvoice function as a consequence of a click to ExportInvoice button with the JavaScript code you provided.

Categories

Resources