Javascript - How to put a callback in a callback? - javascript

I have read this:
Callback in a callback?
And I still do not understand how I am meant to do it. Sorry, I am a Python programmer and only just starting to understand JavaScript.
I have this function:
this.getName(function() {
alert("Done");
});
Which has a callback to here:
this.getName = function(callback){
*doing something*
callback();
}
Which works great. The alert doesn't go off until getName() has finished.
However I have another function, which needs to be run after getName() has been run and completed:
this.getDetails = function(){
*Does something*
}
But I haven't got a clue how it is meant to be implemented. I have tried putting it in the first function, but it doesn't work. Any help would be much appreciated!
I have tried this:
this.getName(function(getDetails) {
alert("Done");
this.getDetails();
});

Instead of alerting "done", just call getDetails (or do both):
this.getName( _ => {
this.getDetails();
} );
I switched to an arrow function to use lexical this, but if you don't want to use an arrow function you can also use bind:
this.getName( function ( ) {
this.getDetails();
}.bind( this ) );
or just:
this.getName( this.getDetails.bind( this ) );

Related

Javascript invoke function without parentheses [duplicate]

How do I pass a function as a parameter without the function executing in the "parent" function or using eval()? (Since I've read that it's insecure.)
I have this:
addContact(entityId, refreshContactList());
It works, but the problem is that refreshContactList fires when the function is called, rather than when it's used in the function.
I could get around it using eval(), but it's not the best practice, according to what I've read. How can I pass a function as a parameter in JavaScript?
You just need to remove the parenthesis:
addContact(entityId, refreshContactList);
This then passes the function without executing it first.
Here is an example:
function addContact(id, refreshCallback) {
refreshCallback();
// You can also pass arguments if you need to
// refreshCallback(id);
}
function refreshContactList() {
alert('Hello World');
}
addContact(1, refreshContactList);
If you want to pass a function, just reference it by name without the parentheses:
function foo(x) {
alert(x);
}
function bar(func) {
func("Hello World!");
}
//alerts "Hello World!"
bar(foo);
But sometimes you might want to pass a function with arguments included, but not have it called until the callback is invoked. To do this, when calling it, just wrap it in an anonymous function, like this:
function foo(x) {
alert(x);
}
function bar(func) {
func();
}
//alerts "Hello World!" (from within bar AFTER being passed)
bar(function(){ foo("Hello World!") });
If you prefer, you could also use the apply function and have a third parameter that is an array of the arguments, like such:
function eat(food1, food2) {
alert("I like to eat " + food1 + " and " + food2 );
}
function myFunc(callback, args) {
//do stuff
//...
//execute callback when finished
callback.apply(this, args);
}
//alerts "I like to eat pickles and peanut butter"
myFunc(eat, ["pickles", "peanut butter"]);
Example 1:
funct("z", function (x) { return x; });
function funct(a, foo){
foo(a) // this will return a
}
Example 2:
function foodemo(value){
return 'hello '+value;
}
function funct(a, foo){
alert(foo(a));
}
//call funct
funct('world!',foodemo); //=> 'hello world!'
look at this
To pass the function as parameter, simply remove the brackets!
function ToBeCalled(){
alert("I was called");
}
function iNeedParameter( paramFunc) {
//it is a good idea to check if the parameter is actually not null
//and that it is a function
if (paramFunc && (typeof paramFunc == "function")) {
paramFunc();
}
}
//this calls iNeedParameter and sends the other function to it
iNeedParameter(ToBeCalled);
The idea behind this is that a function is quite similar to a variable. Instead of writing
function ToBeCalled() { /* something */ }
you might as well write
var ToBeCalledVariable = function () { /* something */ }
There are minor differences between the two, but anyway - both of them are valid ways to define a function.
Now, if you define a function and explicitly assign it to a variable, it seems quite logical, that you can pass it as parameter to another function, and you don't need brackets:
anotherFunction(ToBeCalledVariable);
There is a phrase amongst JavaScript programmers: "Eval is Evil" so try to avoid it at all costs!
In addition to Steve Fenton's answer, you can also pass functions directly.
function addContact(entity, refreshFn) {
refreshFn();
}
function callAddContact() {
addContact("entity", function() { DoThis(); });
}
I chopped all my hair off with that issue. I couldn't make the examples above working, so I ended like :
function foo(blabla){
var func = new Function(blabla);
func();
}
// to call it, I just pass the js function I wanted as a string in the new one...
foo("alert('test')");
And that's working like a charm ... for what I needed at least. Hope it might help some.
I suggest to put the parameters in an array, and then split them up using the .apply() function. So now we can easily pass a function with lots of parameters and execute it in a simple way.
function addContact(parameters, refreshCallback) {
refreshCallback.apply(this, parameters);
}
function refreshContactList(int, int, string) {
alert(int + int);
console.log(string);
}
addContact([1,2,"str"], refreshContactList); //parameters should be putted in an array
You can also use eval() to do the same thing.
//A function to call
function needToBeCalled(p1, p2)
{
alert(p1+"="+p2);
}
//A function where needToBeCalled passed as an argument with necessary params
//Here params is comma separated string
function callAnotherFunction(aFunction, params)
{
eval(aFunction + "("+params+")");
}
//A function Call
callAnotherFunction("needToBeCalled", "10,20");
That's it. I was also looking for this solution and tried solutions provided in other answers but finally got it work from above example.
Here it's another approach :
function a(first,second)
{
return (second)(first);
}
a('Hello',function(e){alert(e+ ' world!');}); //=> Hello world
In fact, seems like a bit complicated, is not.
get method as a parameter:
function JS_method(_callBack) {
_callBack("called");
}
You can give as a parameter method:
JS_method(function (d) {
//Finally this will work.
alert(d)
});
The other answers do an excellent job describing what's going on, but one important "gotcha" is to make sure that whatever you pass through is indeed a reference to a function.
For instance, if you pass through a string instead of a function you'll get an error:
function function1(my_function_parameter){
my_function_parameter();
}
function function2(){
alert('Hello world');
}
function1(function2); //This will work
function1("function2"); //This breaks!
See JsFiddle
Some time when you need to deal with event handler so need to pass event too as an argument , most of the modern library like react, angular might need this.
I need to override OnSubmit function(function from third party library) with some custom validation on reactjs and I passed the function and event both like below
ORIGINALLY
<button className="img-submit" type="button" onClick=
{onSubmit}>Upload Image</button>
MADE A NEW FUNCTION upload and called passed onSubmit and event as arguments
<button className="img-submit" type="button" onClick={this.upload.bind(this,event,onSubmit)}>Upload Image</button>
upload(event,fn){
//custom codes are done here
fn(event);
}
By using ES6:
const invoke = (callback) => {
callback()
}
invoke(()=>{
console.log("Hello World");
})
If you can pass your whole function as string, this code may help you.
convertToFunc( "runThis('Micheal')" )
function convertToFunc( str) {
new Function( str )()
}
function runThis( name ){
console.log("Hello", name) // prints Hello Micheal
}
You can use a JSON as well to store and send JS functions.
Check the following:
var myJSON =
{
"myFunc1" : function (){
alert("a");
},
"myFunc2" : function (functionParameter){
functionParameter();
}
}
function main(){
myJSON.myFunc2(myJSON.myFunc1);
}
This will print 'a'.
The following has the same effect with the above:
var myFunc1 = function (){
alert('a');
}
var myFunc2 = function (functionParameter){
functionParameter();
}
function main(){
myFunc2(myFunc1);
}
Which is also has the same effect with the following:
function myFunc1(){
alert('a');
}
function myFunc2 (functionParameter){
functionParameter();
}
function main(){
myFunc2(myFunc1);
}
And a object paradigm using Class as object prototype:
function Class(){
this.myFunc1 = function(msg){
alert(msg);
}
this.myFunc2 = function(callBackParameter){
callBackParameter('message');
}
}
function main(){
var myClass = new Class();
myClass.myFunc2(myClass.myFunc1);
}

javascript two brackets after function name

What does below syntax means?
connect(mapStateToProps, mapDispatchToProps)(Home)
I understand we are passing two arguments to a function, but what is the purpose of below one?
(Home)
It doesn't look like node but Redux and as in a comment not an ES6 thing.
What it is: Connect is a higher order (factory) function ie. it returns a function. And it is that returned function which is immediately called with Home
Take a look and an example of mock of connect below
function connect(param1, param2) {
return innerFunction (innerParam) {
console.log(`${param1} ${innerParam} ${param2}`)
}
}
connect('A','B')('precedes')
// outputs 'A precedes B'
Edit: Added an example.
A function can return a function, and you can call this returned function immediately.
For information and as already stated in comments, the fact of decomposing one function call into smaller like this one in your example is called currying and is a common practice in JavaScript (more info here : What is 'Currying'?)
This example might help you :
function function1(info) {
return function(innerParam) {
console.log(`Hello this function has info ${info} and has just been called with this param: ${innerParam}` )
}
}
function1('Bobby')('Alice');
// same as :
var bobbyFunction = function1('Bobby');
bobbyFunction('Alice');
This is useful to dynamically generate a function that depends on some parameter, but can still be called several time with some other changing parameters. Imagine this, for instance :
var bobbyFunction = function1('Bobby');
['Alice', 'Tommy', 'Johny'].forEach(name => bobbyFunction(name));
It's plain javascript. Function connect returns another function and code immediately calls it with parameter Home.
function first(f) {
return function second(s) {
console.log(f, s);
}
}
// this
first('one')('two');
// is same as this
var x = first('one');
x('two');
see this example:
connect(mapStateToProps, mapDispatchToProps)(Home)// just like code below
function f(){
//do something
}
function connect(a,b){
return f;
}
connect(mapStateToProps, mapDispatchToProps);//first,return f;
connect(mapStateToProps, mapDispatchToProps)(Home)//second,return f(home);

jQuery Ajax How do callbacks work?

Hello fellow programmers! I just started an additional programming project and swore to god my code will bo SO much cleaner and easily upgradeable than it has been before.
Then I stumbled upon my "arch enemy" the jQuery AJAX returning. Last time I wanted to return something from an AJAX call I had to bend over and just make the call synchronous. That made things sticky and ugly and I hope that this time I will find something better.
So I have been googling/searching stackoverflow for a while now, and just don't understand this solution many ppl has gotten which is called callback function. Could someone give me an example on how I could exploit these callback functions in order to return my login statuses:
function doLogin(username, password) {
$.ajax({
url: 'jose.php?do=login&user='+username+'&pass='+password,
dataType: 'json',
success: function(data) {
if(data.success==1) {
return('1');
} else {
return('2');
}
$('#spinner').hide();
},
statusCode: {
403:function() {
LogStatus('Slavefile error: Forbidden. Aborting.');
$('#spinner').hide();
return (3);
},
404:function() {
LogStatus('Slavefile was not found. Aborting.');
$('#spinner').hide();
return (3);
},
500:function() {
LogStatus('Slavefile error: Internal server error. Aborting.');
$('#spinner').hide();
return (3);
},
501:function() {
LogStatus('Slavefile error: Not implemented. Aborting.');
$('#spinner').hide();
return (3);
}
},
async: true
});
}
So as you probably know, you cannot use return the way I have done from inside an AJAX call. You should instead use callback functions which I have no idea of how to use.
I'd be VERY greatful if someone could write me this code using callback functions and explaining to me just HOW they WORK.
EDIT:
I REALLY need to return stuff, not use it right away. This function is being called from within another function and should be able to be called from different places without being rewritten even slightly.
/EDIT
Sincerly,
Akke
Web Developer at Oy Aimo Latvala Ab
There are three parts to the basic "I need an asynchronous callback" pattern:
Give the function a callback function parameter.
Call the callback function instead of returning a value.
Instead of calling the function and doing something with its return value, the return value will be passed to your callback function as a parameter.
Suppose your synchronous mind wants to do this:
function doLogin(username, password) {
// ...
return something;
}
switch(doLogin(u, p)) {
case '1':
//...
break;
case '2':
//...
break;
//...
}
but doLogin has to make an asynchronous call to a remote server. You'd just need to rearrange things a little bit like this:
function doLogin(username, password, callback) {
return $.ajax({
// ...
success: function(data) {
if(data.success == 1)
callback('1');
else
callback('2');
},
//...
});
}
var jqxhr = doLogin(u, p, function(statusCode) {
switch(statusCode)) {
case '1':
//...
break;
case '2':
//...
break;
//...
}
});
The jqxhr allows you to reference the AJAX connection before it returns, you'd use it if you needed to cancel the call, attach extra handlers, etc.
A callback is simply a function that runs when certain conditions are met. In this case, it is when ajax has a "success".
You are already using a callback, but you don't recognize it. success: function(data) {} is a callback, but it's just what's called an anonymous function. It has no name or reference, but it still runs. If you want to change this anonymous function to a named function, it is really simple: take the code in the anonymous function, and put it in a named one, and then just call the named one:
[...]success: function(data) {
if(data.success==1) {
return('1');
} else {
return('2');
}
$('#spinner').hide();
}, [...]
should change to:
[...]success: function(){ callbackThingy(data) }, [...]
And now just create the callbackThingy function:
function callbackThingy(data){
if(data.success==1) {
someOtherFunction('1');
} else {
someOtherFunction('2');
}
$('#spinner').hide();
}
Note that the "return" value does nothing. It just stops the callback function, whether you are in an anonymous function or a named one. So you would also have to write a second function called someOtherFunction:
function someOtherFunction(inValue){
if(inValue=='1') {
// do something.
} else if(inValue=='2') {
// do something else.
}
}
The above example is if you have to pass parameters. If you do not need to pass parameters, the setup is simpler:
[...]success: callbackThingy, [...]
function callbackThingy(){
// do something here.
}
From the edit in your original post, I can see that you just need to store a (more) global variable. Try this:
// in the global scope , create this variable:
// (or -- at least -- in the scope available to both this ajax call
// and where you are going to use it)
var valHolder = -1;
// then edit your ajax call like this:
[...]
success: function(data) {
if(data.success==1) {
valHolder = 1;
} else {
valHolder = 2;
}
$('#spinner').hide();
},
[...]
Now you can verify 3 things:
valHolder = -1 means that the ajax call has not yet returned successfully
valHolder = 1 means data.success = 1
valHolder = 2 means data.success != 1.
Another option is to store the variable in an HTML attribute of some element.
Finally, you should probably look at jquery.data for the most jquery way of managing stored data.
Does this help?
Just as a small point of interest, you don't have to include
async : true;
as part of your $.ajax options. The default setting for async is already "true".
Sorry to post this as a response, but until I have 50 rep I can't make a simple comment. (Feel free to help me out with that! ^_^ )

Any way to avoid using anonymous functions in jQuery?

If I have a chunk of code like this:
.hover(
function () {
hoverState($("#navbar a").index(this),1);
},
function () {
hoverState($("#navbar a").index(this),-1);
});
Is there any way to get rid of the anonymous functions and just say:
.hover(
hoverState($("#navbar a").index(this),1),
hoverState($("#navbar a").index(this),-1);
);
No, because otherwise your call:
hoverState($("#navbar a").index(this),1)
would evaluate at the same time as the call to the hover function itself. Since Javascript supports closures and first-class functions, you could make a wrapper function:
function wrapper(position){
function _f(){
hoverState($("#navbar a").index(this), position);
}
return _f;
}
And then use:
.hover(
wrapper(1),
wrapper(-1),
)
But the gains of such an approach are questionable.
The reason for the anonymous function is to defer the call to hoverState until the hover event happens. Without some function reference there, you end up calling hoverState and the result of the function call becomes the parameter to the hover method, which is certainly not what you want. The alternative would be to have a named function, but that's really no better and, in some ways, actually worse.
There's a way to do something like this, with the jLambda plugin.
// Without plugin:
$('.foo').click(
function() {
$(this).hide();
$('p').show();
$('a').width(20);
});
// With plugin:
$('.foo').click($l.hide().$('p').show().$('a').width(20));
My answer can seem stupid but here goes... you can use simple functions :}
function hoverStateProxy1() {
hoverState($("#navbar a").index(this),1);
}
function hoverStateProxy2() {
hoverState($("#navbar a").index(this),-1);
}
.hover(hoverStateProxy1, hoverStateProxy2);
As long as you passing reference to function you are OK. It can be both anonymous or not.
You could use JavaScript's "Apply" Function. Here is an example taken from the Prototype.js framework (bind implementation, though it should probably be renamed if not being used from within the framework).
EDIT: Corrected, see This Post
if (!Object.bind) {
Function.prototype.bind= function(owner) {
var that= this;
var args= Array.prototype.slice.call(arguments, 1);
return function() {
return that.apply(owner,
args.length===0? arguments : arguments.length===0? args :
args.concat(Array.prototype.slice.call(arguments, 0))
);
};
};
}
Usage:
.hover(
hoverState.bind(this,$("#navbar a").index(this),1),
hoverState.bind(this,$("#navbar a").index(this),-1)
);

JQuery callback question

I'm trying to assign a different number to different callback functions in jquery.
for (i=o;i<types.length;i++) {
$('#ajax'+types[i]+'Div').html('Loading...').load('searchAjax.php','new=u',function () { $(this).find('select').change( function() { AjaxDiv(i); } ) } );
}
Everytime I run this section of code, i is 5 for each call to ajaxDiv because it is calling a global variable. I'm not sure if I can either change the scope of i or if there's a way to print the value in the change function. Any ideas?
Thank you in advance! Happy Thanksgiving!
Andrew
The callback functions all refer to the same i variable, and they are executed when the loop is finished.
You have to capture the i variable on the loop:
for (i=o;i<types.length;i++) {
(function (i) {
$('#ajax'+types[i]+'Div').html('Loading...').load('searchAjax.php','new=u',
function () {
$(this).find('select').change( function() { AjaxDiv(i); } )
} );
})(i);
}

Categories

Resources