JavaScript: Passing parameters to a callback function
Asked Answered
H

17

365

I'm trying to pass some parameter to a function used as callback, how can I do that?

This is my try:

function tryMe(param1, param2) {
  alert(param1 + " and " + param2);
}

function callbackTester(callback, param1, param2) {
  callback(param1, param2);
}

callbackTester(tryMe, "hello", "goodbye");
Homebrew answered 11/8, 2010 at 13:5 Comment(6)
What you are doing should work. What problems do you have?Kwangchow
Your code works fine, what is the problem?Caporal
It should work... jsfiddle.net/QXQZjTry
sorry it was my fault on main code syntax, I thought was this because this is the first time I use a callback in JavaScriptHomebrew
If you want to add parameters to a callback but can't change what's calling it (as in you have no power to change the argument order, you can pre-bind some of the callbacks parameters with JS bind, as I've shown on this answer: https://mcmap.net/q/93634/-pass-additional-parameter-to-javascript-callback-function-duplicateDialectics
Good question. But I seriously hate code without comments.Jelena
S
320

If you want something slightly more general, you can use the arguments variable like so:

function tryMe(param1, param2) {
  alert(param1 + " and " + param2);
}

function callbackTester(callback) {
  callback(arguments[1], arguments[2]);
}

callbackTester(tryMe, "hello", "goodbye");

But otherwise, your example works fine (arguments[0] can be used in place of callback in the tester)

Strew answered 11/8, 2010 at 13:13 Comment(4)
So long as we're being in the spirit of being general, callback.apply(arguments) as the function body for callbackTester is extensible beyond the two argument scenario.Azole
sorry, it was a syntax error in the main code, I thought was this because this is the first time I use a callback in JavaScript, you've helped me to understand it wasn't the probelm, and to see a great example.Homebrew
FYI, using an anonymous function (Marimuthu's answer) or .bind() (Andy's answer) are much cleaner ways to pass arguments to a callback.Poppy
let args = Object.values(arguments); args.shift(); callback(...args); as callbackTester body allows variable amount of argumentsTerrill
R
248

This would also work:

// callback function
function tryMe(param1, param2) {
  alert(param1 + " and " + param2);
}

// callback executer 
function callbackTester(callback) {
  callback();
}

// test function
callbackTester(function() {
  tryMe("hello", "goodbye");
});

Another Scenario :

// callback function
function tryMe(param1, param2, param3) {
  alert(param1 + " and " + param2 + " " + param3);
}

// callback executer 
function callbackTester(callback) {
  //this is the more obivous scenario as we use callback function
  //only when we have some missing value
  //get this data from ajax or compute
  var extraParam = "this data was missing";

  //call the callback when we have the data
  callback(extraParam);
}

// test function
callbackTester(function(k) {
  tryMe("hello", "goodbye", k);
});
Risk answered 11/8, 2010 at 13:33 Comment(4)
This works great because it also allows the anonymous function to pass in parameters like so: callbackTester (function(data) {tryMe(data, "hello", "goodbye"); });Laminous
I also like to check that the callback is, in fact, a function. if (typeof window[callback] == 'function') window[callback].call(this);Sitter
This is the simple & best answer.Goudy
if you are in a loop. arguments will lose its value, this only works then it is called once, and with arguments that are contants. is better use .bind() methodLaurenlaurena
M
80

Your question is unclear. If you're asking how you can do this in a simpler way, you should take a look at the ECMAScript 5th edition method .bind(), which is a member of Function.prototype. Using it, you can do something like this:

function tryMe (param1, param2) {
    alert (param1 + " and " + param2);
}

function callbackTester (callback) {
    callback();
}

callbackTester(tryMe.bind(null, "hello", "goodbye"));

You can also use the following code, which adds the method if it isn't available in the current browser:

// From Prototype.js
if (!Function.prototype.bind) { // check if native implementation available
  Function.prototype.bind = function(){ 
    var fn = this, args = Array.prototype.slice.call(arguments),
        object = args.shift(); 
    return function(){ 
      return fn.apply(object, 
        args.concat(Array.prototype.slice.call(arguments))); 
    }; 
  };
}

Example

bind() - PrototypeJS Documentation

Midian answered 11/8, 2010 at 13:13 Comment(6)
Out of interest, what's the difference between Array.prototype.slice.call(arguments) and arguments.slice()?Shepherd
@sje397: arguments isn't a *real* array, so it doesn't have a slice() method. However, the slice() method on the Array.prototype is intentionally generic, so you can pass any object that has numerical indexes and a length property and it will work.Midian
This is the most elegant answerPoppy
This .bind() is really great and extend a lot the use & simplicity of callbacks. As a basic sample to understand it, if you have: f = function(arg1,arg2){alert(arg1+arg2);}.bind(this,"abc"); f("def") // Gives "abcdef"Brasilein
This is really a grt answer. Awesome and work well for me. Thank you :)Knotting
thanks, bind saved my day - otherwise, callback was being called while passing it as a parameter to another functionCrumbly
N
20

If you are not sure how many parameters are you going to be passed into callback functions, use apply function.

function tryMe (param1, param2) {
  alert (param1 + " and " + param2);
}

function callbackTester(callback,params){
    callback.apply(this,params);
}

callbackTester(tryMe,['hello','goodbye']);
Nevsa answered 5/4, 2018 at 19:56 Comment(0)
K
14

When you have a callback that will be called by something other than your code with a specific number of params and you want to pass in additional params you can pass a wrapper function as the callback and inside the wrapper pass the additional param(s).

function login(accessedViaPopup) {
    //pass FB.login a call back function wrapper that will accept the
    //response param and then call my "real" callback with the additional param
    FB.login(function(response){
        fb_login_callback(response,accessedViaPopup);
    });
}

//handles respone from fb login call
function fb_login_callback(response, accessedViaPopup) {
    //do stuff
}
Kareykari answered 18/9, 2013 at 22:47 Comment(0)
S
6

Wrap the 'child' function(s) being passed as/with arguments within function wrappers to prevent them being evaluated when the 'parent' function is called.

function outcome(){
    return false;
}

function process(callbackSuccess, callbackFailure){
    if ( outcome() )
        callbackSuccess();
    else
        callbackFailure();
}

process(function(){alert("OKAY");},function(){alert("OOPS");})
Springhalt answered 24/10, 2013 at 7:34 Comment(0)
P
5

Code from a question with any number of parameters and a callback context:

function SomeFunction(name) {
    this.name = name;
}
function tryMe(param1, param2) {
    console.log(this.name + ":  " + param1 + " and " + param2);
}
function tryMeMore(param1, param2, param3) {
    console.log(this.name + ": " + param1 + " and " + param2 + " and even " + param3);
}
function callbackTester(callback, callbackContext) {
    callback.apply(callbackContext, Array.prototype.splice.call(arguments, 2));
}
callbackTester(tryMe, new SomeFunction("context1"), "hello", "goodbye");
callbackTester(tryMeMore, new SomeFunction("context2"), "hello", "goodbye", "hasta la vista");

// context1: hello and goodbye
// context2: hello and goodbye and even hasta la vista
Phosphor answered 11/5, 2015 at 19:33 Comment(0)
3
5

Use curried function as in this simple example.

const BTN = document.querySelector('button')
const RES = document.querySelector('p')

const changeText = newText => () => {
  RES.textContent = newText
}

BTN.addEventListener('click', changeText('Clicked!'))
<button>ClickMe</button>
<p>Not clicked<p>
3d answered 9/7, 2017 at 13:17 Comment(0)
P
3

Faced this recently, to get it(especially if the parent function has multiple arguments doing different stuffs not related to the callback , is to have the callback placed with its argument in an arrow function passed as an argument.

function tryMe(param1, param2) {
  alert(param1 + " and " + param2);
}

function callbackTester(callback, someArg, AnotherArg) {
  callback();
  
}

callbackTester(()=> tryMe("hello", "goodbye"), "someArg", "AnotherArg");

...or simply if you dont have multiple arguments doing other stuff.

function tryMe(param1, param2) {
  alert(param1 + " and " + param2);
}

function callbackTester(callback) {
  callback();
}

callbackTester(()=> tryMe("hello", "goodbye"));

Poodle answered 6/6, 2022 at 8:17 Comment(0)
F
1

A new version for the scenario where the callback will be called by some other function, not your own code, and you want to add additional parameters.

For example, let's pretend that you have a lot of nested calls with success and error callbacks. I will use angular promises for this example but any javascript code with callbacks would be the same for the purpose.

someObject.doSomething(param1, function(result1) {
  console.log("Got result from doSomething: " + result1);
  result.doSomethingElse(param2, function(result2) {
    console.log("Got result from doSomethingElse: " + result2);
  }, function(error2) {
    console.log("Got error from doSomethingElse: " + error2);
  });
}, function(error1) {
  console.log("Got error from doSomething: " + error1);
});

Now you may want to unclutter your code by defining a function to log errors, keeping the origin of the error for debugging purposes. This is how you would proceed to refactor your code:

someObject.doSomething(param1, function (result1) {
  console.log("Got result from doSomething: " + result1);
  result.doSomethingElse(param2, function (result2) {
    console.log("Got result from doSomethingElse: " + result2);
  }, handleError.bind(null, "doSomethingElse"));
}, handleError.bind(null, "doSomething"));

/*
 * Log errors, capturing the error of a callback and prepending an id
 */
var handleError = function (id, error) {
  var id = id || "";
  console.log("Got error from " + id + ": " + error);
};

The calling function will still add the error parameter after your callback function parameters.

Fiveandten answered 29/9, 2016 at 8:59 Comment(0)
D
1

Let me give you a very plain Node.js style example of using a callback:

/**
 * Function expects these arguments: 
 * 2 numbers and a callback function(err, result)
 */
var myTest = function(arg1, arg2, callback) {
  if (typeof arg1 !== "number") {
    return callback('Arg 1 is not a number!', null); // Args: 1)Error, 2)No result
  }
  if (typeof arg2 !== "number") {
    return callback('Arg 2 is not a number!', null); // Args: 1)Error, 2)No result
  }
  if (arg1 === arg2) {
    // Do somethign complex here..
    callback(null, 'Actions ended, arg1 was equal to arg2'); // Args: 1)No error, 2)Result
  } else if (arg1 > arg2) {
    // Do somethign complex here..
    callback(null, 'Actions ended, arg1 was > from arg2'); // Args: 1)No error, 2)Result
  } else {
    // Do somethign else complex here..
    callback(null, 'Actions ended, arg1 was < from arg2'); // Args: 1)No error, 2)Result
  }
};


/**
 * Call it this way: 
 * Third argument is an anonymous function with 2 args for error and result
 */
myTest(3, 6, function(err, result) {
  var resultElement = document.getElementById("my_result");
  if (err) {
    resultElement.innerHTML = 'Error! ' + err;
    resultElement.style.color = "red";
    //throw err; // if you want
  } else {
    resultElement.innerHTML = 'Result: ' + result;
    resultElement.style.color = "green";
  }
});

and the HTML that will render the result:

<div id="my_result">
  Result will come here!
</div>

You can play with it here: https://jsfiddle.net/q8gnvcts/ - for example try to pass string instead of number: myTest('some string', 6, function(err, result).. and see the result.

I hope this example helps because it represents the very basic idea of callback functions.

Danyelledanyette answered 24/2, 2019 at 10:48 Comment(0)
I
1
function tryMe(param1, param2) {
  console.log(param1 + " and " + param2);
}

function tryMe2(param1) {
  console.log(param1);
}

function callbackTester(callback, ...params) {
  callback(...params);
}



callbackTester(tryMe, "hello", "goodbye");

callbackTester(tryMe2, "hello");

read more about the spread syntax

Intoxication answered 29/7, 2019 at 21:34 Comment(1)
Best answer for me. Most practical.Phaedrus
L
1

I'm trying to pass some parameter to a function used as callback, how can I do that?

I think he is implying that he wants to call the function this callbackTester(tryMe, "hello", "goodbye"). To do this we can use the Rest Operator (...). This operator takes the arguments that a function receives and dumps them into a real array that we will use to access in our callback function.

Now, some other developers might also argue that we could use the arguments "array". That will be fine, but we should be careful with it. arguments is not a real array but an array-like object with a length property.

Here is a working snippet using the Rest Operator:

function tryMe(params) {
  console.log(params.join(', '));
}

function callbackTester(callback, ...params) {
  callback(params);
}

callbackTester(tryMe, 'hello', 'goodbye', 'hi again');
callbackTester(tryMe, 'hello', 'goodbye');
callbackTester(tryMe, 'hello');
Lemley answered 30/9, 2021 at 14:52 Comment(0)
C
1

Just use the bind() function which is primarily used to set the this value. However, we can also use it to pass parameters without calling the function due to bind() returning a new function with the sequence of arguments provided.

Example:

function foo(param1, param2, param3) {
  console.log(param1, param2, param3);
}

setTimeout(foo.bind(null, 'foo', 'bar', 'baz'), 1000);

In the snippet above, the setTimeout function takes 2 arguments, the callback function and a minimum time in ms for the function to be called, so when passing the callback function we're going to use bind and specify the parameters

Note: The first parameter of bind is the value that we want to set for this, and because we're not interested on that, null was passed, the subsequent parameters in bind are going to be the parameters for the callback.

Cyanate answered 28/8, 2022 at 5:25 Comment(0)
L
0

I was looking for the same thing and end up with the solution and here it's a simple example if anybody wants to go through this.

var FA = function(data){
   console.log("IN A:"+data)
   FC(data,"LastName");
};
var FC = function(data,d2){
   console.log("IN C:"+data,d2)
};
var FB = function(data){
   console.log("IN B:"+data);
    FA(data)
};
FB('FirstName')

Also posted on the other question here

Linkage answered 18/1, 2017 at 11:38 Comment(0)
B
0
//Suppose function not taking any parameter means just add the GetAlterConfirmation(function(result) {});
GetAlterConfirmation('test','messageText',function(result) {
                        alert(result);
    }); //Function into document load or any other click event.


function GetAlterConfirmation(titleText, messageText, _callback){
         bootbox.confirm({
                    title: titleText,
                    message: messageText,
                    buttons: {
                        cancel: {
                            label: '<i class="fa fa-times"></i> Cancel'
                        },
                        confirm: {
                            label: '<i class="fa fa-check"></i> Confirm'
                        }
                    },
                    callback: function (result) {
                        return _callback(result); 
                    }
                });
Bordelon answered 31/10, 2019 at 14:21 Comment(2)
Please add an explanation of what you're doing and why :)Anacoluthon
Okay, I'll do from my next answer, sorry for the above because this is my first answer.Bordelon
M
0

You can pass your params using an array, I hope this will work for you thanks

function tryMe(params) {
    alert(params[0] + " and " + params[1]);
  }
  
  function callbackTester(callback, params) {
    callback(params);
  }
  
  callbackTester(tryMe, ["hello", "goodbye"]);

OR

function tryMe(param1, param2) {
    alert(param1 + " and " + param2);
  }
  
  function callbackTester(callback, params) {
    callback(params[0],params[1]);
  }
  
  callbackTester(tryMe, ["hello", "goodbye"]);
Moriyama answered 25/7, 2023 at 15:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.