My series of methods are like so :
onUpdateAcrossDown ( findAcrossAndDownWords( across_index, down_index ) )
I want to reuse findAcrossAndDownWords, so I'd like it to return my two objects that I can pass into other methods if need be.
findAcrossAndDownWords: function(across_index, down_index) {
across_word = across_index[0] // <-- not real, just representing that it becomes an object here.
down_word = down_index[0]
return [across_word, down_word] // <-- This is where my problem is. Not sure how to return a double param for my parent function.
}
The trouble is, the return I am using does not properly pass across_word, down_word .
onUpdateAcrossDown: function(across_word, down_word) {
// How do I get across_word and down_word here properly?
If you want to use the values in an array as parameters to a function, you have to call the function with .apply()
var results = findAcrossAndDownWords( across_index, down_index );
onUpdateAcrossDown.apply(whatever, results);
The .apply() method takes two arguments: the value to use for this in the called function, and an array containing the parameters to pass.
You could, instead of nesting calls, pass the second function as an argument:
findAcrossAndDownWords(across_index, down_index, onUpdateAcrossDown);
function findAcrossAndDownWords(object1, object2, callNext)
{
//do stuff
return callNext(object1, object2);
}
Or, change the function definition of the second function to:
function UpdateAcrossDown(anArray)
{
var obj1 = anArray[0], obj2 = anArray[1];
}
Or, if you're allways going to call the same function:
function findAcrossAndDownWords(object1, object2, callNext)
{
//do stuff
return UpdateAcrossDown(object1, object2);//loses call context
return UpdateAcrossDown.apply(this,arguments);//preserve called context
//or even
return UpdateAcrossDown.apply(this,[object1,object2]);//preserve called context
}
Related
I am writing a wrapper that accepts a callback function to pass on to another function or execute directly. The problem is that another functions have bound parameters with callback parameter having a different argument number. Therefore initial binding would accept a string placeholder that needs to be replaced. But how?
function callback(){}
function asyncfunc1(a,b,callback,d){ callback();}
function asyncfunc2(a,b,c,callback){ callback();}
function asyncfunc3(callback,b,c,d){ callback();}
function wrap(cond,func,callback){
if (cond) {
// here I want to execute the passed function
// however instead of real callback, I have a placeholder bound
// so how do I bind it again to replace it with real callback?
func();
}
else callback();
}
wrap(cond,asyncfunc1.bind(null,param1,param2,'callback',param3),callback)
// this is what it's used for, is to create a flow of conditional callbacks
wrap(cond1,asyncfunc1.bind(null,param1,param2,'callback',param4),function(){
wrap(cond2,asyncfunc2.bind(null,param1,param2,param3,'callback'),function(){
wrap(cond3,asyncfunc3.bind(null,'callback',param2,param3,param4),callback
}
})
I am going to avoid bind and pass a function with arguments as an array.
function wrap(cond,fn_arr,callback){
if (cond) {
if (fn_arr instanceof Array){
var func=fn_arr.shift();
if (fn_arr.includes('callback')) {
fn_arr[fn_arr.indexOf('callback')] = callback;
}
func(...fn_arr)
} else fn_arr();
}
else callack();
}
Then with little array manipulation will do the replacement trick.
wrap(cond,[asyncfunc,param1,param2,'callback',param4],callback)
I have the following test code:
var async = require('async');
var GROUP = 'testGroup';
var opts = {
someKey: 'hi',
};
test(opts);
function test(options) {
async.series([
doThis.bind(null, options),
doThat.bind(null, options),
], function(results) {
debugger;
});
}
function doThis(options, cb) {
options.someKey = [GROUP, options.someKey].join('.');
return cb();
}
function doThat(options, cb) {
debugger;
options.someKey = [GROUP, options.someKey].join('.');
return cb();
}
When we hit the debugger in doThat(), options.someKey already has the value someGROUP.hi, so when the function finishes we end up with options.someKey === 'someGROUP.someGroup.hi'
How do we bind such that the original object does not change? The bind is necessary because we need to pass in options to the functions that run within async.series. Otherwise, we could just invoke the functions and pass in the object as a parameter.
I'm don't think your partially applying the options parameter to your doThis(), doThat() functions is especially pertinent.
You're passing the same javascript object/literal as aparameter to two functions and and then mutate that parameter.
If you don't to mutate that object then don't. Find some other way of returning the results of your operation. doThis() and doThat() could return values instead of modifying the parameter. You could gather them up in the final callback after the series gets called.
If you just want to preserve the intital value of opts, use lodash or something to make a deep clone of opts before you pass it into test.
As the title says I'm wondering if it's possible to get the parameters of a passed function. After hours of searching and looking at similar questions I'm still no closer, so I'll attach a simple example rather then what I'm working on - as I'm starting to suspect it's not possible.
Intended global function
function getTransaction(anyMethod)
{
db.transaction
(
function(transaction)
{
anyMethod(transaction);
},
function errorCB(err) {
redirectToLoginWithError("Error processing SQL");
},
function successCB() {
;//alert("Success!");
}
);
}
Functions to be called
function iWork(tx)
{
tx.doSomething();
}
function iDontWork(tx, param1, param2)
{
tx.doSomething(param1, param2);
}
Actual call
// Works fine
getTransaction(iWork);
// The problem
getTransaction(iDontWork, value1, value2);
getTransaction(iDontWork2, value1, value2, ..., valueX);
I've tried several different approaches, but none have proved successful so far. The closest (although not very) have been
getTransaction(function(){iDontWork(value1, value2)}));
This does call the correct function via the getTransaction, but does not pass the parameters correctly: Params (value1, value2) are kept, but the transaction object is lost / undefined. I can see why this does happen, but I cannot see any solution to it. All said, I'm also open to that the getTransaction should be scrapped and re-written somehow. The point is to get a flexible method that scales well.
Simply refactor getTransation to take a function and an array of arguments. Prepend the transaction variable to the argument array and call the function using apply:
function getTransaction(anyMethod, methodArgs) {
var someFunction = anyMethod;
// if no args provided, use an empty array
methodArgs = methodArgs || [];
db.transaction (
function(transaction) {
// transaction is always the first arg; prepend it to the arg list
methodArgs.unshift(transaction);
// call method with argument array
anyMethod.apply(null, methodArgs);
},
// ...
);
}
Simply use it with:
doTransaction(iDontWork, [param1, param2]);
doTransaction(iWork);
EDIT:
As #rambo coder pointed out, you could just use regular arguments (instead of an array of arguments) by slicing arguments:
function getTransaction(anyMethod) {
var someFunction = anyMethod;
db.transaction (
function(transaction) {
var methodArgs = arguments.slice(1);
methodArgs.unshift(transaction);
anyMethod.apply(null, methodArgs);
},
...
This way lets you supply arguments directly to getTransaction, as you do in your example (doTransaction(iDontWork, param1, param2);), instead of putting them in an array.
getTransaction(function (x) {
iDontWork(x, value1, value2);
});
Your getTransaction assumes that its single argument is a function that takes one parameter. You need to create a new function that takes one parameter, but also includes the specific parameter values you want (namely value1 and value2).
The above uses an anonymous function; you could also do it with a named function:
function forwarder(x) {
iDontWork(x, value1, value2);
}
getTransaction(forwarder);
You can do it by creating partial functions:
function iDontWork(param1, param2){
return function(tx) {
tx.doSomething(param1, param2);
}
}
And:
getTransaction(iDontWork(value1, value2));
I have a requirement where I get the anchor tags id and based on the id I determine which function to execute.. so is there anything that suites below code
function treeItemClickHandler(id)
{
a=findDisplay(id);
a();
}
You can assign a function to a variable like so:
You can also return a function pointer from a function - see the return statement of findDisplay(id).
function treeItemClickHandler(id)
{
var a= findDisplay;
var other = a(id);
other();
}
function findDisplay(id)
{
return someOtherThing;
}
function someOtherThing()
{
}
Sure, functions are first class objects in JavaScript. For example, you can create a map (an object) which holds references to the functions you want to call:
var funcs = {
'id1': function(){...},
'id2': function(){...},
...
};
function treeItemClickHandler(id) {
if(id in funcs) {
funcs[id]();
}
}
As functions are treated as any other value, you can also return them from another function:
function findDisplay(id) {
// whatever logic here
var func = function() {};
return func;
}
functions are normal javascript values, so you can pass them around, (re)assign them to variables and use them as parameter values or return values for functions. Just use them ;) Your code is correct so far.
You can map between ids and functions to call in a number of ways.
One of the simpler ones is to create an object mapping ids to functions, and find the function to call from that object (this is in essence a nicer-looking switch statement).
Example:
function treeItemClickHandler(id)
{
var idMap = {
"some-id": findDisplay,
"another-id": doSomethingElse
};
if (!idMap.hasOwnProperty(id)) {
alert("Unknown id -- how to handle it?");
return;
}
// Call the corresponding function, passing the id
// This is necessary if multiple ids get handled by the same func
(idMap[id])(id);
}
function findDisplay(id)
{
// ...
}
function doSomethingElse(id)
{
// ...
}
This question in summary is to figure out how to pass variables between javascript functions without: returning variables, passing parameters between primary functions, using global variables, and forcing function 1 to wait for function 2 to finish. I figured out a jQuery solution and posted in below (in the answers section).
Old Post: I initialize a set of four functions, each calling on each other in a different way. At the end of it, I need the final modified product (an array) returned to the initializing function.
Global variables don't force the initial function to wait. And returning it backwards four times doesn't work either. How do you pass a modified variable back to its initializing function, if you can't return it? Or why isn't it returning?
(the maze starts at initFunctionA, ends at functionD)
classOne = {
initFunctionA : function() {
classTwo.functionB(functionD, array);
// I NEED ACCESS TO ARRAY2 HERE
},
functionD : function(data, array) {
var array2 = // modifications to array
}
}
{...}
classTwo = {
functionB : function(callback, array) {
$.ajax({
success: function(ret){
classTwo.functionC(ret, callback, array)
}
});
},
functionC : function(ret, callback, array) {
callback(ret.data.x, array);
}
}
Change your callback (at the call site) such that you capture the return value of functionD. Then, change functionD so that it returns array2. I've added this access to the example below as a convenience. (Also, be sure to include semicolons where "required" if you want to make JSLint happy.)
classOne = {
initFunctionA : function() {
var self = this;
classTwo.functionB(function() {
var array2 = functionD.apply(self, arguments);
// ACCESS ARRAY2 HERE
}, array);
},
functionD : function(data, array) {
var array2 = // modifications to array
return array2;
}
};
{...}
classTwo = {
functionB : function(callback, array) {
$.ajax({
success: function(ret){
classTwo.functionC(ret, callback, array)
}
});
},
functionC : function(ret, callback, array) {
callback(ret.data.x, array);
}
};
You can't make it work with a pattern like you've written there; it's simply not possible in Javascript because there's no such thing as "waiting". Your ajax code has to take a callback parameter (which you've got, though it's not clear where it comes from or what it does), and that initial function should pass in code to do what you need with the array after the ajax call finishes.
I would use an object constructor:
function ClassOne() {
this.array2 = [];
}
ClassOne.prototype.initFunctionA = function() {
// ...
}
ClassOne.prototype.functionD = function(data, array) {
// Can use array2 EX: this.array2
}
var classOne = new ClassOne();
This is how I understand your problem:
classTwo handles an AJAX call and may modify the result. classOne makes use of classTwo to get some data and needs the resulting data.
If so, how's this:
classOne = {
initFunctionA : function() {
var array = ['a','b','c'];
classTwo.functionB(this.functionD, array);
},
functionD : function(data, array) {
// This function is called when the AJAX returns.
var array2 = // modifications to array
}
}
{...}
classTwo = {
functionB : function(callback, array) {
$.ajax({
success: function(ret){
classTwo.functionC(ret, callback, array)
}
});
},
functionC : function(ret, callback, array) {
callback(ret.data.x, array);
}
}
So classOne.initFunctionA calls classTwo.functionB which sets up an ajax call. When the ajax call completes successfully, classTwo.functionC is called with the result and the initial array. From here, classOne.functionD is called with ret.data.x and the array.
Okay! I found a way to pass variables between functions without:
making global variables
making object properties (Chaos's solution)
passing parameters
These three were suggested here as the only ways.
Accessing variables from other functions without using global variables
But, if you you can't pass parameters directly, and you need one function to wait for the other (i.e, can't rely on references), and you're using asynchronous calls to the server in an intermediate function, then your only solution is:
Using jQuery...
Create this object in the DOM (dynamically if you don't want to muddy your markup):
<div id='#domJSHandler" style="display: none;"></div>
Then in the function that must wait:
//Function & Class Set 2
$('#domJSHandler').bind('proceedWithAction', function(event, param1, param2) {
// action set 2
});
And in the function to be waited on:
//Function & Class Set 1
// action set 1
$('#domJSHandler').triggerHandler('proceedWithAction', [param1, param2]);
Essentially encase the last actions you need to perform in a jQuery bind custom event on an invisible DOM object. Trigger that event from JS with jQuery's triggerHandler. Pass your parameters and voila!
I'm sure SO will give me crap for this (and for narcissistically accepting my own answer) but I think it's pretty brilliant for a uber-newbie and it worked for me.
So :p Stack Overflow
(jk You've all saved my ass many times and I love you all :)