6

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.

2
  • At a high level, the calls need to be chained together: the success function of the first calls the second. Commented Aug 21, 2015 at 16:12
  • i wrote a factory about it have a look Commented Jan 6, 2017 at 18:38

5 Answers 5

5

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

Sign up to request clarification or add additional context in comments.

2 Comments

I will try this - but the line in HTML (request.price) is always coming as undefined - <p ng-repeat="item in fetchRequest(request.price)"></p>
@Leapahead I commented my code to let you understand how a promise works, and what a promise really is. What you must do is setting the response inside the success part of the $http call.
3

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

Comments

1

Your calls are made asynchronously so while the calls are being made, the rest of the code is still executing. Thus,

<p ng-repeat="item in fetchRequest(request.price)"></p>

is executed before request.price is even defined.

What you need to do is chain the calls to your api calls:

$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 
  
  //Loop through requests
  $scope.req_list.foreach(function (elem, index) {
    //chained call is here
    $scope.fetchRequest(elem.price, index);
  });
}).

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

$scope.fetchRequest = function(request, index) {
  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);
    //Attach result of api call to apropriate element of req_list array
    $scope.req_list[index].items = data;

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

}
}

And then change:

<p ng-repeat="item in fetchRequest(request.price)"></p>

To:

<p ng-repeat="item in request.items"></p>

1 Comment

it's make sense
-1

Usually I use following pattern:

$http({method: 'GET',
       url: '<*whatever url is, no need to put it on $scope, unless you really need it there*>'})
    .success(function(result) { return result.data; })
    .error(function(reason) { <handle your error here> })
    .then(function(data) { <make your second request here with the data you've got from the first> });

1 Comment

.success() method is deprecated
-1

Inside the first success call you should call the second one:

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

                    // Second call
                    $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"
                            }];
                        });

                    }

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

            }
        }


    ]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.