For Each loop with promises not working in angularjs

The "types" parameter being passed in is in the format ["hourAverage","hourMedian","dayAverage","dayMedian","weekAverage","weekMedian","monthAverage","monthMedian"]

Source:

$scope.buildCharts = function(types){
    var deferred = $q.defer();
    var promises = [];

    types.forEach(function(type){
                $scope.prepareData(type);
                deferred.resolve([
                {
                    title: type,
                    curveType: 'function',
                    legend: { position: 'bottom' }
                },type]);
                promises.push(deferred.promise);
    });
    return $q.all(promises);
};

Output:

[
  [
    {
      "title": "hourAverage",
      "curveType": "function",
      "legend": {
        "position": "bottom"
      }
    },
    "hourAverage"
  ],
  [
    {
      "title": "hourAverage",
      "curveType": "function",
      "legend": {
        "position": "bottom"
      }
    },
    "hourAverage"
  ],
  [
    {
      "title": "hourAverage",
      "curveType": "function",
      "legend": {
        "position": "bottom"
      }
    },
    "hourAverage"
  ],
  [
    {
      "title": "hourAverage",
      "curveType": "function",
      "legend": {
        "position": "bottom"
      }
    },
    "hourAverage"
  ],
  [
    {
      "title": "hourAverage",
      "curveType": "function",
      "legend": {
        "position": "bottom"
      }
    },
    "hourAverage"
  ],
  [
    {
      "title": "hourAverage",
      "curveType": "function",
      "legend": {
        "position": "bottom"
      }
    },
    "hourAverage"
  ],
  [
    {
      "title": "hourAverage",
      "curveType": "function",
      "legend": {
        "position": "bottom"
      }
    },
    "hourAverage"
  ],
  [
    {
      "title": "hourAverage",
      "curveType": "function",
      "legend": {
        "position": "bottom"
      }
    },
    "hourAverage"
  ]
]

Upvotes: 0

Views: 139

Answers (1)

trincot
trincot

Reputation: 350290

This illustrates that a promise can only resolve with one value. Any further call of resolve on the same deferred object will have no effect. That is why you get the first object as value over and over again. This is required behaviour by the Promises/A+ specifications, point 2.1.2 (emphasis mine):

2.1.2 When fulfilled, a promise:

     2.1.2.1 must not transition to any other state.

     2.1.2.2 must have a value, which must not change.

Of course, if it would have been allowed to change the value of a promise, then you still would not have had the desired result, as then the result would have had a repetition of the last object value .

To solve this, create a new deferred object within the loop, so that you always resolve a new promise:

Move this:

var deferred = $q.defer();

Into the forEach callback:

types.forEach(function(type){
    var deferred = $q.defer();
    // etc...

Upvotes: 2

Related Questions