Conditional Chaining of $http-calls with Promises in AngularJS
Asked Answered
H

3

6

I have to execute three different $http-calls sequentially which depend on each other. Until now my working solution is something like this:

$http.get(".../1/...").success(function() {
    $http.get(".../2/...").success(function() {
        $http.get(".../3/...").success(function() {
            
        });
    });
});

Now there is a certain change to be made: The first call should be skipped if a condition is true. I could do it like this:

if (skipCallOne) {
    $http.get(".../2/...").success(function() {
        $http.get(".../3/...").success(function() {
            
        });
    });
}
else {
    $http.get(".../1/...").success(function() {
        $http.get(".../2/...").success(function() {
            $http.get(".../3/...").success(function() {
                
            });
        });
    });
}

This obviously leads to massive code replication. I see that this could be reduced, if I used proper functions for the particular $http-calls. But as I understand, a better solution would be to use the $http-promises and properly chain them, like this:

$http.get(".../1/...").then(function() {
    return $http.get(".../2/...");
}).then(function() {
    return $http.get(".../3/...");
}).then(function() {
    
});

But now my question is, how can I conditionally skip the first call with the least code replication?

Hepta answered 5/5, 2015 at 15:6 Comment(0)
G
12

You can try this approach:

$q.when(skipCallOne || $http.get(".../1/..."))
  .then(function() {
    return $http.get(".../2/...");
  }).then(function() {
    return $http.get(".../3/...");
  }).then(function() {
});
Garges answered 5/5, 2015 at 15:15 Comment(2)
This looks exactly like something I hoped to see. But I'm not sure if I understand the use of $http.get(...).then. You aren't calling then, why is that?Hepta
Fully agree with you here. I edited my answer. Let's have a look at the documentation: .when(value) wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. This is useful when you are dealing with an object that might or might not be a promise, or if the promise comes from a source that can't be trusted.Garges
N
4

You can wrap the $http.get calls in functions that test the condition and return the $http.get promise if the conditions apply or a pre-resolved promise if not.

function callOne() {
    if(condition) {
        return $http.get(".../1/...");
    } else {
        var deferred = $q.defer();
        deferred.resolve();
        return deferred.promise;
    }
}

callOne().then(function() {
    return $http.get(".../2/...");
})
Nutt answered 5/5, 2015 at 15:16 Comment(1)
Actually I think @PhilippAndreychev 's solution is better, since it is more idiomatic to q.Nutt
B
1

I like to be able to see stuff like this working, so I put this little controller together to demonstrate the promises resolving, with a conditional $http.get running first. I don't claim that this is elegant or as clever as the other answers, though I think it is quite similar to Cristian's solution.

Note: One thing that may make this difficult to understand is answers to this question often show chaining $http calls which are only executed, and for the sake of simplicity, the values those calls are returning are ignored and it may not be immediately clear how to break things apart to actually get at the values.

Demo

app.controller('MainCtrl', function($scope, $q, $http) {
  $scope.x = true;

  var firstHttp = function() {
    var deferred = $q.defer()
    if($scope.x) {
      data = 'x was true'
       deferred.resolve(data);
    } else {
      $http.get('test.json')
      .then(function(data) {
        $scope.data1 = data;
        deferred.resolve(data);
      })
    }  
    return deferred.promise
  }

  $scope.myGetterFn = function() {
    firstHttp()
    .then(function(data) 
    {
      data.data ? $scope.data1 = data : $scope.datax = data;
      $http.get('test2.json')
    .then(function(data2) 
    {
        $scope.data2 = data2
        $http.get('test3.json')
    .then(function(data3) 
    {
          $scope.data3 = data3
    })
    })
    })
  }
});
Bribe answered 5/5, 2015 at 16:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.