0

I am using a JavaScript API of some software. In software there are Solutions and they contain Worklists.

For each Solution I want to list Worklists.

solutions = obtainSolutionsformAPI();
for (i=0,i<solutions.length,i++){
    sol=solutions[i];
    sol.obtainWorklists(callbackFunction);    
}

the callbackFunction is called by software and the array of worklists is passed as the argument.

function callbackFunction(arrayOfWorkLists){
    for (j=0,j<arrayOfWorkLists.length,j++){
        wl=arrayOfWorkLists[j];
        console.log(wl);
    }
}

now in console.log I would like to also print out the i variable (the number of solution) together witch each worklist, but how do I get the i inside callback function, when I am not the one who is calling it? I suspect I need to modify the callback function each time before I pass it to sol.obtainWorklists(callbackFunction); What is the correct way of doing this?

Edit: I do not want the function defintions to be nested (one inside other), because I have multiple nestings like this one and it would be quite unreadable. So I do not want this:

sol.obtainWorklists(function callbackFunction(arrayOfWorkLists){...}); 

2 Answers 2

2

You can use a builder function:

sol.obtainWorklists(buildCallback(i, callbackFunction));

...where buildCallback looks like this:

function buildCallback(index, func) {
    return function() {
        var args = [index];
        args.push.apply(args, arguments);
        func.apply(this, args);
    };
}

Complete example below

Then in your callback, expect the i value as the first argument with the arguments that obtainWorklists normally provides following it.

How that works:

  • When you call buildCallback, you pass in the i value and the callback you want called.
  • buildCallback returns a new function which has that information bound to it (it's a closure over the index and func arguments in the call to buildCallback).
  • When obtainWorklists calls the function buildCallback created, we create an array with the i value (index) followed by the arguments that were received from obtainWorklists.
  • Then we call the callback, using the same this value that the function was called with, and the args array; your callback will see the entries in args as discrete arguments.

If you don't care about the this value in your callback, you can use ES5's Function#bind instead:

sol.obtainWorklists(callbackFunction.bind(null, i));

That does much the same thing, but doesn't preserve the this used to call it.


Complete example for builder function (live copy):

// obtainWorklists stand-in
function obtainWorklists(func) {
    setTimeout(function() {
        // Just call it with a random number
        func(rand(100, 200));
    }, rand(100, 500));
}

// Code to get worklists
var i;
for (i = 0; i < 10; ++i) {
    obtainWorklists(buildCallback(i, callback));
}

function buildCallback(index, func) {
    return function() {
        var args = [index];
        args.push.apply(args, arguments);
        func.apply(this, args);
    };
}


// Your callback
function callback(index, value) {
    display("Index is " + index + ", value is " + value);
}

// ========= Utility functions
function rand(min, max) {
    return Math.floor(Math.random() * (max - min)) + min;
}
function display(msg) {
    var p = document.createElement('p');
    p.innerHTML = String(msg);
    document.body.appendChild(p);
}

Complete example for Function#bind (live copy):

// obtainWorklists stand-in
function obtainWorklists(func) {
    setTimeout(function() {
        // Just call it with a random number
        func(rand(100, 200));
    }, rand(100, 500));
}

// Code to get worklists
var i;
for (i = 0; i < 10; ++i) {
    obtainWorklists(callback.bind(null, i));
}

// Your callback
function callback(index, value) {
    display("Index is " + index + ", value is " + value);
}

// ========= Utility functions
function rand(min, max) {
    return Math.floor(Math.random() * (max - min)) + min;
}
function display(msg) {
    var p = document.createElement('p');
    p.innerHTML = String(msg);
    document.body.appendChild(p);
}
Sign up to request clarification or add additional context in comments.

3 Comments

I tried to use the sol.obtainWorklists(callbackFunction.bind(null, i)); but it did not work. It worked, once I removed null from arguments of bind(). But the problem is that the printed i for all worklists is the i=solutions.length -1 since it is all asynchroneous and the printing occurs when i is already i=solutions.length -1
@nothinkelse: You need the null (or undefined) there, and within your callback, use the first argument passed to the function, not i.
@nothinkelse: I've added live examples of both ways. If you don't care what this is in the callback, Function#bind is probably the better way to go (but be sure all of your target environments have it; IE8 doesn't, for instance, it needs a shim).
2

You need to use a closure:

solutions = obtainSolutionsformAPI();
for (i=0,i<solutions.length,i++){
    (function(innerI) {
        sol=solutions[innerI];
        sol.obtainWorklists(function(worklists) {
            callbackFunction(worklists, innerI);
        }
    })(i);
}

function callbackFunction(arrayOfWorkLists, i){
    console.log(i);
    for (j=0,j<arrayOfWorkLists.length,j++){
        wl=arrayOfWorkLists[j];
        console.log(wl);
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.