1

I'm trying to get multiple APIs to access data but after all this returned empty data without displaying any error. Here is my code:

 var myApp = angular.module("myApp", []);

 // Main controller
 myApp.controller("appCtrl", ["$scope", "$http", function($scope, $http){

   // Variables of stations, train number and departure date
   var sta = "";
   var trainNum = "";
   var deptDate = "";

   // Get stations data  
   $http.get("https://rata.digitraffic.fi/api/v1/metadata/stations.json").then(function(response){
     // Load the stations data
     $scope.stations = response.data;

     // Access all stations data
     angular.forEach($scope.stations, function(value,index){

       sta = $scope.stations[index].stationShortCode;
       //console.log(sta);

       // Get train data from each station
       $http.get("https://rata.digitraffic.fi/api/v1/live-trains?station=" + sta + ".json").then(function(response){
         $scope.trains = response.data;
         //console.log(response.data);

         // Access all train data
         angular.forEach($scope.trains, function(value, index){
           trainNum = $scope.trains[index].trainNumber;
           deptDate = $scope.trains[index].departureDate;

         // Get all train compositions data from all train data above
         $http.get("https://rata.digitraffic.fi/api/v1/compositions/" + trainNum + "?departure_date=" + deptDate + ".json").then(function(response){
           $scope.trainCompositions = response.data;
           //console.log(response.data);
         });
       });
     });
   });
 });
}]);

The first API url responded well, however from the second one it returned empty arrays. I wanted to get all data of the railways stations from the 1st API, then concat each station into the 2nd API url, after that I want to get data of trainNum (train number) and deptDate (departure date) to concat into the 3rd API url to access all data of the train compositions there.

Here is examples of

2nd API url: https://rata.digitraffic.fi/api/v1/live-trains?station=HKI (where HKI is Helsinki station).

3rd API url: https://rata.digitraffic.fi/api/v1/compositions/960?departure_date=2017-05-02 (where 960 is the train number, and 2017-05-02 is departure date).

Thank you guys in advance.

2
  • I think the problem here is, the $http service makes requests async, but your first forEach doesn't wait for the inner request to finish. either try making the inner request in a synchronized way or better change the API, so you only have to make one async call (it will be much faster than what you currently are doing). 😉 Commented Jul 22, 2017 at 21:28
  • Thank your for your explanation, the code below of Jake Holzinger solved all the problems here Commented Jul 22, 2017 at 22:41

1 Answer 1

2

This is a great problem for promises. We just need to change some things around so we can rely on them properly.

We're going to want to "chain" these promises to achieve the desired effect. This mostly involves returning the promises created inside of another promise callback. We'll also have to introduce the $q dependency so we can resolve multiple promises concurrently.

var myApp = angular.module("myApp", []);

// Main controller
myApp.controller("appCtrl", ["$scope", "$http", "$q", function ($scope, $http, $q) {

    // Get stations data  
    $http.get("https://rata.digitraffic.fi/api/v1/metadata/stations.json").then(function (response) {
        // Load the stations data
        $scope.stations = response.data;

        // We need to map the following requests into an array of promises so we can resolve them concurrently.
        var stationPromises = $scope.stations.map(function (station) {
            // Use the "angular way" to define query parameters.
            return $http.get("https://rata.digitraffic.fi/api/v1/live-trains", {
                params: { station: station.stationShortCode }
            }).then(function (response) {

                // Assign this set of trains to the station so we don't overwrite other staions trains...
                station.trains = response.data;

                // Another set of promises to get all of the departure information for each train.
                var trainPromises = station.trains.map(function (train) {
                    // Lets use the "angular way" to define parameters again.
                    return $http.get("https://rata.digitraffic.fi/api/v1/compositions/" + train.trainNumber, {
                        params: { departure_date: train.departureDate }
                    }).then(function (response) {
                        // Assign this set of compositions to the train so we don't overwrite other compositions for other trains...
                        train.compositions = response.data;
                    });
                });

                return $q.all(trainPromises);
            });
        });

        // Resolve all of the promises.
        return $q.all(stationPromises);
    }).catch(function (err) {
        // Something bad happended...
        console.error(err);
    });
}]);
Sign up to request clarification or add additional context in comments.

6 Comments

Well, I can't thank you enough for this. I have learnt a lot from those codes.
By the way, now I can render all station name by returning {{station.stationName}} under ng-repeat directive "station in stations", but I can't do the same thing with trains and train compositions because they are multiple arrays and no $scope parameters for station.trains and train.compositions according to your code. Do you know a solution for this?
You should just use ng-repeat on the station.trains within the ng-repeat for the stations. Here's a simple fiddle: jsfiddle.net/ez0wwrsb
Thank you very much. However, the data is pretty much and it loads pretty long in my computer, now I just want to search a specific station to make only one request on that station, and then this passes the station parameters into the API station. For example, I create a search box and submit button, when I type "Helsinki" and click the submit button in front page, the API will be "rata.digitraffic.fi/api/v1/live-trains?station=HKI" to load the data. What do you think about this? I'm sorry for annoying you too much on this, but I desire to learn more :(
I would recommend a dropdown to select the station so you don't have to guess. I would also recommend following some tutorials so you can learn these basic features on your own, I can't do everything for you :). Good luck! jsfiddle.net/ez0wwrsb/1
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.