5

I'm trying to use the value from the first ajax call in the second ajax call. I'm using the code structure below. For some reason the second call returns undefined for the userLocation variable. How could I refactor my code so that the userLocation value from the first ajax call can be used in the url of the second ajax call?

var userLocation;

function getUserLocation() {
  $.ajax({
    url: 'https://www.example.com/location.json',
    success: function(response) {
      userLocation = response.coordinates;
    }
  });
}

function getCurrentWeather() {
  $.ajax({
    url: 'https://www.example.com/weather' + userLocation +  '.json',
    success: function(response) {
      console.log(response);
    }
  });
}


$(document).ready(function() {
  $.when(
    getUserLocation()
  ).done(
    getCurrentWeather()
  )
});

UPDATE 1: Thanks to the answers provided below I've been able to refactor my code. Now the value received from the first ajax call can be used in the second ajax call. Here is the updated code:

var userLocation;

function getUserLocation() {
  return $.ajax('https://www.example.com/location.json')
  .then(function(response) {
    return JSON.parse(response);
  }).then(function(json) {
    // data from the location.json file is available here
    userLocation = json.coordinates;
  })
}

function getCurrentWeather() {
  return $.ajax('https://www.example.com/weather' + userLocation +  '.json');
}


getUserLocation().then(getCurrentWeather).then(function(data) {
  // data from the weather(userLocation).json file is available here
});
Piotr Berebecki
  • 7,428
  • 4
  • 33
  • 42

4 Answers4

9

jQuery's ajax returns promises, which you can use:

function getUserLocation() {
  return $.ajax('https://www.example.com/location.json'); // note the `return`
}

function getCurrentWeather(userLocation) {
  return $.ajax('https://www.example.com/weather' + userLocation +  '.json');
}

getUserLocation().then(getCurrentWeather).then(function(data) {
   // location data here
});

Or, more verbosely

getUserLocation().then(function (user) { 
    return getCurrentWeather(user); 
}).then(function(data) {
   // location data here
});

The better solution would be to make it a single call rather than two calls since making a lot of AJAX calls slows down your application - especially on mobile devices with limited bandwidth.


Here is a callback based approach that is likely inferior to the promise based one (for example with error handling) - but I feel like we should show it for completeness. You can read about the general solution in this thread.

function getUserLocation(callback) {
  $.ajax('https://www.example.com/location.json', callback)
}

function getCurrentWeather(userLocation, callback) {
  $.ajax('https://www.example.com/weather' + userLocation +  '.json', callback);
}

getUserLocation(function(user) {
   getCurrentWeather(user, function(weather) {
       console.log("Got weather", weather); 
   });
});
Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • 1
    I also have no idea why this code is inside a `$(document).ready` - that just slows thing down for no reason. – Benjamin Gruenbaum Apr 24 '16 at 07:26
  • I've added an updated code where I've followed your solution and also I've removed the`$(document).ready`. I've slightly modified the approach, for example I'm not passing the argument to the `getCurrentWeather()` function. It achieves the desired outcome, although I'm not sure if it follows a good practice. – Piotr Berebecki Apr 24 '16 at 17:28
  • 1
    You are using mutable global state, this is bad - it will cause unwanted bugs and is very far from a good practice. The problem with this sort of code is debugging it not writing it. – Benjamin Gruenbaum Apr 24 '16 at 17:47
  • I just couldn't make it work using strictly your promises solution. In which function should I assign the coordinates obtained from the `location.json` file to the `userLocation` variable so that it can be passed to the `getCurrentWeather()`? Or maybe I shouldn't be using the userLocation as a variable? Also where can I process the weather data? This is my main objective, however in your solution you commented that location data (not the weather data) can be processed in the last part of the code. This confuses me as I was hoping that I could start processing the weather data at this stage. – Piotr Berebecki Apr 24 '16 at 19:39
  • 1
    Doing `getUserLocation().then(getCurrentWeather).then(function(data) { /*location data*/ });` really does `getUserLocation().then(function(location) { return getCurrentWeather(location); }).then(function(data) { ...` - promises chain - data is transferred via the first argument between them - this is that fact in action. – Benjamin Gruenbaum Apr 24 '16 at 21:22
  • I was able to modify my code and follow your guidance more closely. I've set up a working mock-up of the weather app on codepen [link](http://codepen.io/PiotrBerebecki/pen/ONoJKL). Before I republish this on SO, would you mind providing some further feedback so that I can follow good practices and update my question with my findings? Much appreciated. – Piotr Berebecki Apr 25 '16 at 05:31
2

For some reason the second call returns undefined for the userLocation variable

This is because you are not returning the promise from the ajax call, see Benjamin's answer on how to do this.

How could I refactor my code so that the userLocation value from the first ajax call can be used in the url of the second ajax call?

Refactor your code to nest the call to the other function inside the first call:

var userLocation;

function getUserLocation() {
  $.ajax({
    url: 'https://www.example.com/location.json',
    success: function(response) {
      // set the user location
      userLocation = response.coordinates;
      // make call to second function passing in userLocation
      getCurrentWeather(userLocation);
    }
  });
}

function getCurrentWeather(userLocation) {
  $.ajax({
    url: 'https://www.example.com/weather' + userLocation +  '.json',
    success: function(response) {
      console.log(response);
    }
  });
}

$(document).ready(function() {
    getUserLocation()
});

If your not using the variable userLocation anywhere else then save a bit of code:

function getUserLocation() {
  $.ajax({
    url: 'https://www.example.com/location.json',
    success: function(response) {
      // make call to second function passing in coordinates from response
      getCurrentWeather(response.coordinates);
    }
  });
}

function getCurrentWeather(userLocation) {
  $.ajax({
    url: 'https://www.example.com/weather' + userLocation +  '.json',
    success: function(response) {
      console.log(response);
    }
  });
}

$(document).ready(function() {
    getUserLocation()
});
cnorthfield
  • 3,384
  • 15
  • 22
1

You should be doing this:

function getUserLocation() {
  return $.ajax({
    url: 'https://www.example.com/location.json',
    success: function(response) {
      userLocation = response.coordinates;
    }
  });
}

function getCurrentWeather(userLocation) {
  return $.ajax({
    url: 'https://www.example.com/weather' + userLocation +  '.json',
    success: function(response) {
      console.log(response);
    }
  });
}


$(document).ready(function() {
  $.when(
    getUserLocation()
  ).done(
    getCurrentWeather
  )
});
  1. return the $.ajax(...) from getUserLocation
  2. getCurrentWeather is pass as a function, you shouldn't call it in the done, it will called async after getUserLocation is done.

Edit #2: What you are doing wrong in puting getCurrentWeather() into the .done(...) is that this function will call immediately. However, .done(...) should passed in a function, where the function will be called after the $.when() promise is resolved.

As Benjamin Gruenbaum mentioned, it is better to use .done(...) then .then(...)

Community
  • 1
  • 1
Tan Li Hau
  • 1,984
  • 17
  • 24
  • Your `$.when` doesn't actually do anything and your `done` should probably be a `then`. – Benjamin Gruenbaum Apr 24 '16 at 07:25
  • Agree. I think @Piotr Berebecki should jsut follow your [answer](http://stackoverflow.com/a/36820347/1513547). I initially was trying to just make minor changes on his original code to point out what he wasn't doing right. – Tan Li Hau Apr 24 '16 at 07:33
0

It can be like this :

var userLocation;

function getUserLocation() {
  $.ajax({
    url: 'https://www.example.com/location.json',
    success: function(response) {
      userLocation = response.coordinates;
    }
  }).done(function() {
       getCurrentWeather()
  });
}

function getCurrentWeather() {
  $.ajax({
    url: 'https://www.example.com/weather' + userLocation +  '.json',
    success: function(response) {
      console.log(response);
    }
  });
}
osmanraifgunes
  • 1,438
  • 2
  • 17
  • 43