0

I want to return a zipcode before I call a 2nd service, so that -- from what I thought I know -- I can wrap in a promise, and then ask for the promise later. So I figured I would just place my 2nd service inside the promise of the 1st service. But chaining promises this way is not being friendly.

Angular factory is called up and inside the factory method:

var userGeoPromise = userService.getGeoposition().then(function (geoposition) {
    vm.geoposition = geoposition;
            return addressService.reverseGeocode(geoposition.coords);
    }).then(function (data) {
            vm.currentLocation = googleService.googleAddressComponentsToAddress(data.results[0]);
            zipCodeCurrent = vm.currentLocation.zip;
    });

Notice 2 things above:

  1. I assigned the promise to var userGeoPromise
  2. zipCodeCurrent is set which contains the zipcode

Promise Testing works fine:

userGeoPromise.then( function() {
      console.log('should always show', zipCodeCurrent);
});

2nd service call:

userGeoPromise.then( function() {
     var serviceBase = "http://localhost:2295/api/getservicezip/"+ zipCodeCurrent;
     var serviceZipPromise = $http.get(serviceBase);
     return serviceZipPromise.then(function (results) {
          console.log('serviceZipPromise', results);
          return results.data;
     });
});

But now the site modal just spins when I put the serviceZipPromise.then... inside the other promise.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • I take it `googleService.googleAddressComponentsToAddress` is **not** asynchronous – Jaromanda X Mar 11 '17 at 02:25
  • anything in the console messages to speak of? it could be that `$http.get(serviceBase)` is rejecting (you have absolutely no rejection handlers, so it stands to reason that something is rejecting in the last piece of code) – Jaromanda X Mar 11 '17 at 02:30
  • Well, I am not sure about about this googleservice thing... but it seems like as long as I wait for the thing before calling the other service then it doesn't matter. Earlier I even tried calling a function and wrapping the 2nd service in a the function thinking it would be fine as it is going to end up getting called but that didn't work either. –  Mar 11 '17 at 02:32
  • I can pull this 2nd service call out of the promise call and it works , other than I have to hardcode the zipcode `return serviceZipPromise.then(...` –  Mar 11 '17 at 02:34
  • I can find nothing on the internet about `googleAddressComponentsToAddress` - is that your own function? – Jaromanda X Mar 11 '17 at 02:34
  • rather than using a global (i.e. `zipCodeCurrent` ) try `return vm.currentLocation.zip` - and then in the last piece of code ... `userGeoPromise.then( function(zipCodeCurrent) {` – Jaromanda X Mar 11 '17 at 02:36
  • Oh, ya I inherited some of that code from another developer - that code works fine, the google geo location .. then it gets the zip code based on the lat and long. It is all about that 2nd service which is not happy about waiting –  Mar 11 '17 at 02:36
  • ok - see if there's some error ... `return serviceZipPromise.then(...existing code..).catch(function(err) { console.error(err); })` - you also haven't mentioned if there are any errors in the developer tools console - I suspect there will be – Jaromanda X Mar 11 '17 at 02:37
  • No errors, just spinning as the original caller never returns its promise from another js file that is async and waiting –  Mar 11 '17 at 03:37
  • @JeremyMiller is your second service call needs any data from first service call? – Gangadhar Jannu Mar 11 '17 at 04:45
  • *when I put ... **inside the other promise*** - can you show how your code **actually is** - because I don't quite understand what you mean by that statement – Jaromanda X Mar 11 '17 at 04:54
  • Hey, the OP seems to be onto something. His first answer works except that zipcode is not passed. 2nd answer of the OP , does actually "work" but geez - are you able to write a better answer as the 3 returns etc.. I don't like that code at all. thx in advance –  Mar 11 '17 at 08:15

2 Answers2

0

Switch the order and add in 2 separate error handlers ( which is a good practice btw)

  var serviceZipPromise = $http.get(serviceBase);  // call up 
        return serviceZipPromise.then(function (results) {
            console.log('should always show', zipCodeCurrent);
            userGeoPromise.then(function () {
                //console.log('serviceZipPromise', results);
                console.log('inside servicezip ', zipCodeCurrent);

            }, function (err) {  // error from userGeoPromise
                console.log(err);
            });

             return results.data;  // THIS will return the data
        }, function (err) { // outer error,  this was switched 
            console.log(err);

        });

This should not error, but for your real serviceBase to end up using the zip code, u might have to execute it a bit later

UPDATE answer for you

  // created part of the api call
  var xserviceBase = "http://localhost:2295";  // this looks to be your base

  return userGeoPromise.then(function(){
       return $http.get(xserviceBase + '/api/getserviceablezip/' + zipCodeCurrent).then(function(results){
             return results.data;
       })
  });

Yes, I know that the 3 returns look a bit nasty, but it should work

  • Well, overall I like it, No errors , but issue is STILL going to be that the serviceBase is going to need to be INSIDE as it NEEDS to pass the zip code too –  Mar 11 '17 at 08:06
  • Right, I figured that , ok i'll show an updated answer it is getting late , so i'm not going to put in all the error handling , but my updated answer should "work" for the zip to get passed. –  Mar 11 '17 at 08:07
0

In a then callback you should return the result value, not assign it to zipCodeCurrent (or any other variable). You did this correctly in the first then callback, but you should apply the same principle in the second:

var userGeoPromise = userService.getGeoposition().then(function (geoposition) {
    vm.geoposition = geoposition;
    return addressService.reverseGeocode(geoposition.coords);
}).then(function (data) {
    vm.currentLocation = googleService.googleAddressComponentsToAddress(data.results[0]);
    return vm.currentLocation.zip; // *** return it
});

NB: I did not touch the assignments to the properties of vm, but normally you should avoid mutating variables which (apparently) exist outside of the scope of these callback functions.

The Promise test would look like this:

userGeoPromise.then( function(zipCodeCurrent) { // *** add the argument
    console.log('should always show', zipCodeCurrent);
});

The 2nd service has a nested then call, which is something to avoid. Instead of calling a then on a nested, intermediate promise, return that promise, and apply the then on the main promise chain:

userGeoPromise.then( function(zipCodeCurrent) { // *** add the argument as in the test
    var serviceBase = "http://localhost:2295/api/getservicezip/"+ zipCodeCurrent;
    return $http.get(serviceBase); // *** return the promise
}).then( function (results) { // *** move the then-callback to the outer chain
    console.log('serviceZipPromise', results);
    return results.data;
}).catch( function (error) { // *** add error handling at the end of the chain
    console.log('error occurred:', error);
});

Note how the nesting level is never more than 1.

trincot
  • 317,000
  • 35
  • 244
  • 286