3

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);
  }
}
Kyle Cureau
  • 19,028
  • 23
  • 75
  • 104
  • Javascript arrays are passed by reference, so if you keep passing the same array to the nested functions you should get the modified array in the final call. Could you post the full working code? – axel_c Aug 20 '10 at 13:18
  • That code really doesn't make any sense; `classTwo.function(functionB, array)` in particular. Are you saying that you're going to *call* functionB there? – Pointy Aug 20 '10 at 13:33
  • @axel_c - you're right. sorry. I create another array (array2) in my last function using the first array. I tried to just say array = array2 at the end of it all, but it still didn't work. It's returning the data before the modifications (initFunctionA proceeds without waiting). The code is really long. I made edits above though so hopefully it's more clear. Thanks for your help! – Kyle Cureau Aug 20 '10 at 13:34
  • @Pointy yep, I'm calling functionB there. – Kyle Cureau Aug 20 '10 at 13:35

5 Answers5

1

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.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • I think I figured out a way to mimic "waiting" in javascript regardless of the ajax call. It worked for my purposed but I'd appreciate your opinion. I posted the answer in this answer section. – Kyle Cureau Aug 22 '10 at 05:16
1

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();
ChaosPandion
  • 77,506
  • 18
  • 119
  • 157
  • I believe that the crux of the problem is the asynchronous ajax call in the middle of things; it doesn't really have anything to do with the way the classes are built (though it's kind-of hard to tell, I admit). – Pointy Aug 20 '10 at 13:44
  • @Pointy, I see why you were confused. I had my alphabet crossed :) I fixed the letters. @ChaosPandion ... I'll come back to this tomorrow and try your solution. – Kyle Cureau Aug 20 '10 at 13:58
  • +1 I never got to test this out, because I needed to keep my classes static and organized in the way the rest of the project is. It might work or it may suffer the problems that Pointy brought up. I'm not expert enough to know. I solved my problem in another way (which I posted below)...but +1 cuz this may be a completely valid solution and it looks like it may do exactly what you say. – Kyle Cureau Aug 22 '10 at 05:20
1

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);
  }
};
strager
  • 88,763
  • 26
  • 134
  • 176
  • i tried to implement this solution to the letter, but I'm not getting any data back. Although I'm not throwing any errors either, which is bizarre. I'd look into it further but I already found a solution that works (the one I posted). That being said, you seem to know what you're talking about. I'm an amateur and I don't want to mess up the stack overflow MO, so just give me a "yea, I'm confident" and I'll accept this as the answer. Check out my rebuttal to your comment too, if you have the time. Thanks! – Kyle Cureau Aug 22 '10 at 06:36
  • @Emile, Can you post all your code? Are you sure you're returning `array2` in `functionD`? Are you sure you're writing your code which accesses `array2` in the anonymous function in `initFunctionA` and not outside that anonymous function? – strager Aug 22 '10 at 07:10
  • I did try it and then I reversed my changes. Forgive me for not posting the code (I'm on a deadline and have to go with my hacky solution). BUT...I learned a lot from your approach. I passed array2 along with several other parameters and I may have not understood the nuances of going with more than just one. That being said, +1 and check. I think this will help someone else for sure. – Kyle Cureau Aug 22 '10 at 07:19
  • As I understand it, are you saying that a variable local to function X is available for use within all functions called by function X, even if not passed as an argument? (var self is defined in functionA, which calls functionB which refers to self in its function definition without self being a parameter in the functionB call) Did I pick that up right? – Euan M Oct 16 '17 at 04:11
0

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.

Matt
  • 995
  • 1
  • 8
  • 18
  • excellent understanding of the function order! I'm not sure I see the solution. I need to use array2 at the end of initFunctionA – Kyle Cureau Aug 20 '10 at 14:10
  • You're not going to be able to do that. The solution is to move all the code from initFunctionA that relies on array2 into functionD. It will behave like the function has been split in two pieces with a delay in the middle (caused by the ajax). – Matt Aug 20 '10 at 14:53
  • True that @Matt. Though I just found a solution that does it. Posted below. – Kyle Cureau Aug 22 '10 at 06:13
0

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 :)

Community
  • 1
  • 1
Kyle Cureau
  • 19,028
  • 23
  • 75
  • 104
  • 1
    Dealing with the DOM is dealing with global state. I think this is what "making global variables" meant, not just using JavaScript globals (i.e. properties on `window` in a browser). – strager Aug 22 '10 at 05:54
  • The limitation to global variables as a solution to controlling function order (for instance, when ajax is used), is that the 2nd (3rd, 4th) function carries out its operations on a variable, while the 1st function continues. But I agree with you conceptually. It's just that globals didn't solve my asynchronous problem. This does. (although I just saw your post, let me check it out) – Kyle Cureau Aug 22 '10 at 06:12
  • also, and .unbind() before .bind(...) if user is able to return the that page again. – Kyle Cureau Aug 22 '10 at 08:45
  • This really is not any different than declaring a global function and calling it from the ajax completion handler. Truly, no different at all: the DOM itself is global, so a function bound as an event handler is global by implication. You achieve a level of indirection, as the triggering environment need not know what function will actually run, but you'd get exactly the same effect by having a global variable to refer to the actual function. Of course invoking a global function directly is faster than a custom event, too. – Pointy Aug 22 '10 at 15:11
  • if I use global variables, my first function runs without "waiting." Firing an event from ajax's success means that the function called by the ajax won't fire till it's through, but that called function isn't the one I need to wait. I appreciate your insight but the two methods have produced very different results for me. – Kyle Cureau Aug 23 '10 at 02:48