Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angularjs - Multiple $http REST calls (second call dependent on output of first)

Tags:

http

angularjs

I am a newbie to AngularJs world - I am trying to get data from two REST WS calls.

First one returns a set of data (works fine)- using the value of data from frist one I need to make another webservice call and retrive the data and print in a table.

Below is what I have tried so far: HTML:

<table ng-table="tableParams" id="request_table" class="table table-striped table-bordered" cellspacing="0" width="100%">
<thead>
    <tr>
        <th>Number</th>
        <th>Price</th>
        <th>Short Description</th>
        <th>Requested for</th>
        <th>State</th>
    </tr>
</thead>
<tbody>
    <tr ng-repeat="request in req_list | orderBy:sortType:sortReverse | filter: searchItem">
        <p ng-repeat="item in fetchRequest(request.price)"></p>

        <td>{{request.number }}</td>
        <td>{{request.price}}</td>
        <td>{{request.short_description}}</td>
        <td>{{request.requested_for.display_value}}</td>
        <td>{{request.stage}}</td>
    </tr>

</tbody>

Script:

            angular.module('sc_request_list')
            .controller('MyRequestItems', [
                '$scope',
                '$http',
                function($scope, $http) {
                    $scope.sortType = 'number' //set the default sort type
                    $scope.sortReverse = false; // set the default sort order
                    $scope.searchItem // set the default search/filter term
                    $scope.itemUrl = '/api/sc_request';
                    $scope.reqUrl = '/api/sc_req_item';
                    $http.defaults.headers.common.Accept = "application/json";
                    $scope.fetchRequestItemList = function() {
                        $http({
                            method: 'GET',
                            url: $scope.itemUrl,
                        }).


                        success(function(data, status) {
                            var result = data;
                            var json = JSON.stringify(result);
                            var data = JSON.parse(json);
                            $scope.req_list = data.result; // response data 

                        }).
                        error(function(data, status) {
                            $scope.req_list = [{
                                "req_list": "Error fetching list"
                            }];
                        });

                    }

                    $scope.fetchRequest = function(request) {
                        console.log("Request Number is: " + request);
                        $http({
                            method: 'GET',
                            url: $scope.reqUrl + "/" + request,
                        }).


                        success(function(data, status) {
                            var result = data;
                            var json = JSON.stringify(result);
                            var data = JSON.parse(json);
                            $scope.req = data.result; // response data 

                        }).
                        error(function(data, status) {
                            $scope.req = [{
                                "req": "Error fetching list"
                            }];
                        });

                    }
                }


            ]);

Any help much appreaciated.

like image 446
Leapahead Avatar asked Aug 21 '15 16:08

Leapahead


2 Answers

I would do it like that, with the second call inside the success response.

function getFirstItem(){           // Here I declare a function that will return a promise.
    return $http({
        method: 'GET',
        url: $scope.itemUrl
    });
}

function getDependantItem(){         // I declare a second function that returns  a promise
    return $http({
        method: 'GET',
        url: $scope.otherUrl
    });
}

$scope.fetchRequest = function(request) {      // Here is a function that can be called by  the view.
    getFirstItem()
        /*
         * I call the first function that returns a promise. 
         * the "then" is just setting a 
         * callback that will be executed when your server will respond.
         * The next thing the code does, after registering the callback,
         * is going to the end of your function,
         * and return nothing.
         */
     .then(function(result1){
        $scope.req = result1.result; // Now that the server has answered, you can assign the value to $scope.req, and then, call the second function.

        getDependantItem().then(function(result2){
            // This is still an async call. The code keeps on running, and
            // you will only have this callback running when your server will have responded

            // Handle your response here and assign your response to a $scope variable.
        }, function(error2){
             // If an error happened during the second call, handle it here.
        });

    }, function(error1){ 
        // If an error happened during first call, handle it here.
    });

    // If you want to return something, you must do it here.
    // Before your promises would ever be resolved
    // That's the reason why you got an undefined
};

Few things can be noted about your code :

  • Avoid .success and .error, use .then(function(success){}, function(error){});. The 2 firsts are deprecated from most of the frameworks, and the angular doc doesn't speak about it at all anymore.
    https://docs.angularjs.org/api/ng/service/$q

  • Avoid putting everything in the $scope. Just put things that need to be shared with the view, or other controllers.

  • ASAP, learn about services to share functionalities, and have 1 layer of your application responsible for 1 thing

like image 76
Deblaton Jean-Philippe Avatar answered Oct 20 '22 05:10

Deblaton Jean-Philippe


With $q service, you can chain your promise objects like this:

$scope.fn1 = function(){
  var deferred = $q.defer();
  $http.({ method: 'GET', url: 'YOUR_1st_API' }).success(function(data){
    deferred.resolve(data);
  });
  return deferred.promise;
}

$scope.fn2 = function(data){
  var deferred = $q.defer();
  $http.({ method: 'GET', url: 'YOUR_2nd_API' }).success(function(data){
    deferred.resolve(data);
  });
  return deferred.promise;
}

// after $scope.fn1() is done pass data with resolve method to $scope.fn2() , now you can access data from fn1 inside fn2
$scope.fn1().then($scope.fn2);

And it would be better if you separate your business logic like data fetching to "service" or "factory" and inject them to your controller. With this way your code will be a lot easier to read and maintain.

More info for $q service

like image 24
murnax Avatar answered Oct 20 '22 06:10

murnax