Question

I've recently started with Angular and would really appreciate some help on how to properly structure my code the angular way. This is more of a meta question rather then technical question.

I have an app that retrieves some data from the server on startup. An important thing to notice here is that I have to use multiple requests to the server instead of just one request to fetch the data. (This is done because the data is retrieved from multiple 3rd-party APIs and it is quicker to retrieve it one by one)

I also need to execute some code when all the data is loaded and on each iteration as well (I calculate average score in this example)

My controller looks something like this:

angular.module('app', []).
  controller('myController', function() {
    $scope.data = [];
    $scope.averageScore = 0;

    var requests = ['something', 'other_thing'];
    var scoreCount = 0;
    // Load data
    for(var i=0; i<requests.length; i++) {
      myService.getData(requests[i]).then(function(response) {
        $scope.data.push(response.data);
        // Calculate average score
        scoreCount += response.data.score;
        $scope.averageScore = scoreCount/$scope.data.length;

        if($scope.data.length == requests.length) {
          // All data is loaded, execute some code..
        }
      });
    }

  });

Then in the template I have an ng-repeat:

<div class="items-container" ng-controller="myController">
  <h1> Average score: {{averageScore}}</h1>

  <div class="item-block" ng-repeat="item in data">
    <span> {{item.name}} </span>
    <span> {{item.score}} </span>
  </div>
</div>

What I don't like about this setup is that in my actual app the loop that loads the data is a lot "bigger" and has some more actions performed on the received data.

I thought that abstracting each data item into a directive and performing the required actions inside of it would be a better approach, but I've read in other discussions that using services to retrieve data in directives is not considered a good practice. I also don't know how I would be able to tell when all the data is loaded if each item was a directive.

Would be great if someone could point me in the right direction on how this kind of app could be properly structured in angular.

Was it helpful?

Solution

You could use $q.all() to execute all you requests in parallel, and only have the callback called when all the promises are fulfilled:

$q.all([myService.getData('something'), myService.getData('other_thing')]).
    then(function(array) {
        var somethingResponse = array[0];
        var otherThingResponse = array[1];
        ...
    });

If you need work done on each retrieved data, then you should do it in the service:

function getSomething() {
    return getData('something').then(function(response) {
        return transformResponse1(response);
    });
}

function getOtherTthing() {
    return getData('other_thing').then(function(response) {
        return transformResponse2(response);
    });
}

Indeed, then() returns a new Promise which is resolved via the return value of the success callback.

And if you need to do something when all the transformed responses are available, then you can do it in the globall callback:

$q.all([myService.getSomething(), myService.getOtherThing()]).
    then(function(array) {
        var transformedResponse1 = array[0];
        var transformedResponse2 = array[1];
        // do what you need here
    });    
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top