0

I have the following type of structure:

(function(){

var objects = [];

$('button.one').on('click', function(){

  fetchObjects = function(objects) {
    $.post("/fetchObjects")
      .done(function(data){
        objects = data;
        console.log(objects.length);
      });
  }
  fetchObjects(objects)

});

$('button.two').on('click', function(){
  console.log(objects.length);
});

})();

You can see I have a variable objects that is local to this function. Initially its empty. When I click button.one I wish to populate objects with the returned value from some ajax request. It appears to work, however when clicking button.two, the objects variable is still an empty array.

Why isn't objects available in the jQuery callback?

I've also tried this approach but with the same results:

function callback(data) {
  facilities = data
}

$.post("/fetchObjects")
.done(function(data){
  callback(data);
});

What am I missing here? Please don't tell me to make "objects" global.

Jake Wilson
  • 88,616
  • 93
  • 252
  • 370

2 Answers2

1

I don't know why you're passing objects as parameter. The following should work fine I think. Please let me know if you're trying to achieve something else.

(function(){

var objects = [];

$('button.one').on('click', function(){

  fetchObjects = function() {
    $.post("/fetchObjects")
      .done(function(data){
        objects = data;
        console.log(objects.length);
      });
  }
  fetchObjects()

});

$('button.two').on('click', function(){
  console.log(objects.length);
});

})();
Chirag Mongia
  • 545
  • 4
  • 12
0

Let's simplify the code a bit. You have essentially this:

var objects = [];

fetchObjects = function(innerObjects) {
  var data = ['a','b'];
  innerObjects = data;
  console.log(innerObjects.length);
};

fetchObjects(objects);
console.log(objects);

(I've changed the other objects variable's name just for clarity; the issue is the same even if it had the same name.)

When you call the function, innerObjects contains a reference to objects so modifying it would change the original array as well. But when you do

innerObjects = data;

now instead of modifying the array you're replacing the reference with something else. innerObjects "points" to data instead of objects and the original variable remains unchanged.

To make it work you'd need to loop through the data array (assuming it'll always be an array) and assign the contents to the objects reference one by one. This way you'll keep the original reference and modify the original array.

var objects = [];

fetchObjects = function(innerObjects) {
  var data = ['a','b'];
 
  for( var i = 0; i < data.length; i++ ) {
      innerObjects[i] = data[i];
  }
  console.log(innerObjects.length);
};

fetchObjects(objects);
console.log(objects);

Or, in your actual code:

(function(){

var objects = [];

$('button.one').on('click', function(){

  fetchObjects = function(objects) {
    $.post("/fetchObjects")
      .done(function(data){
        for( var i = 0; i < data.length; i++ ) {
          objects[i] = data[i];
        }
        console.log(objects.length);
      });
  }
  fetchObjects(objects)

});

$('button.two').on('click', function(){
  console.log(objects.length);
});

})();
JJJ
  • 32,902
  • 20
  • 89
  • 102
  • why don't access objects directly from within the method? you don't need to loop nor pass objects as a parameter... – acontell Feb 01 '15 at 09:08
  • @acontell The function now works for any array that's passed to it. If you remove the parameter and the loop then it will work for only one hardcoded variable. – JJJ Feb 01 '15 at 09:10
  • That's what I'm confused about. Instead of using `innerObjects` at all, why can't I just say `objects = data`? Because then I would think that I'm replacing the `objects` variable with the stuff from `data`. Why does that not work? – Jake Wilson Feb 01 '15 at 09:11
  • @Jakobud that would work, thanks to scope, objects is available within the function and you can assign the retrieve data directly to it but not using a parameter as Juhana pointed out – acontell Feb 01 '15 at 09:12
  • 1
    @Jakobud You need to realize that you have *two* variables called `objects`. When you do `objects = data` you're replacing the *local variable* with `data`. The outer variable is left unchanged. – JJJ Feb 01 '15 at 09:13
  • That's exactly the point, but if you don't pass it as a parameter and use directly objects, it should work – acontell Feb 01 '15 at 09:14
  • @Juhana let me make this question easier. Lets say instead of `objects` being an array, what if it was a boolean? What if I needed to set `objects = true` within my `.done()` function? – Jake Wilson Feb 01 '15 at 09:16
  • That would be impossible with the setup you have now because unlike arrays, booleans aren't passed by reference. You'd have to remove the parameter and modify the variable directly in the function. – JJJ Feb 01 '15 at 09:18
  • I tried that. Seems like it didn't work. I got rid of the `fetchObjects` function completely and just did the `$.post` and tried to access `objects` directly. Doesn't seem to work even though I feel like it should. – Jake Wilson Feb 01 '15 at 09:19
  • I suggest you take a look at http://stackoverflow.com/a/3638034/502381 if you're unfamiliar with how object references are passed in JavaScript. – JJJ Feb 01 '15 at 09:19
  • Thanks for the help. I am using CoffeeScript and I just realized I think CoffeeScript is re-declaring `objects` as a local var in my button click handler. I think that's the whole problem. Thanks again. – Jake Wilson Feb 01 '15 at 09:28