0

I want to create an array containing some objects

Firstly, I get a first array from the server containing a list of devices like this

 [ 
{accountID : "sysadmin",deviceID : "123"},
{accountID : "sysadmin",deviceID : "3"}
    ...
    ]

Then I create a second array containing some objects that each object represent a device(deviceID) and contains an array of events of this device that I get from the server

I do a loop upon the first array like this :

$scope.myArrayofDevices = [];

angular.forEach(response, function(device){ 

    $scope.myObject={};

    $scope.myObject.device = device.deviceID;

    $http.get('events')
        .success(function (data) {

        $scope.myObject.events = data;        

        });


        $scope.myArrayofDevices.push($scope.myObject);

    });//end for loop 

I get events data from the server correctly .

But, when I check $scope.myArrayofDevices array I get an the first object with only the deviceID and no event array and the second object with deviceID and events array correctly

like this :

[
{deviceID : 123, events:},
{deviceID : 3 , events : array[5]}
]

How can I solve this issue ?

Note that I try to assign an array to $scope.myObject.events it works perfectly the problem is using a loop with $http

Taha
  • 1,072
  • 2
  • 16
  • 29
  • 2
    Try to define a new variable `myObject` inside the forEach callback function. use `var myObject = {}` instead of `$scope.myObject = {}` – Titus Apr 14 '17 at 11:43
  • thank you @Titus your idea solved my problem – Taha Apr 14 '17 at 13:04

4 Answers4

3

You can use $q.all() to resolve an array of promises and get the final result

angular.module('app', []);

angular.module('app').controller('ExampleController', ['$scope', '$q', function($scope, $q) {

    $scope.myArrayofDevices = [];

    $scope.getDeviceObject = function(deviceId) {
        return $http.get('events/' + deviceId).then(function(deviceEvents) {
            return {
                "device": deviceId,
                "events": deviceEvents
            };
        });
    }

    var promises = [];

    angular.forEach(response, function(device) {
        promises.push($scope.getDeviceObject(device.deviceID));
    });

    /*
     * Combines multiple promises into a single promise
     * that will be resolved when all of the input promises are resolved
     */
    $q.all(promises).then(function(devices) {
        $scope.myArrayofDevices = $scope.myArrayofDevices.concat(devices);
    });


}]);    
Stephane Janicaud
  • 3,531
  • 1
  • 12
  • 18
  • Deferred anti-pattern. – dfsq Apr 14 '17 at 12:12
  • Answer edited to better match question.@dfsq you're probably right but I don't have a better answer at the moment and I think it's not that bad. I would love to read a better one ! ^^ – Stephane Janicaud Apr 14 '17 at 12:31
  • 1
    Just remove $deferred, it's not needed. `$scope.getDeviceEvents = function(deviceId) { return $http.get('events/'+deviceId).then(function(response) { return response.data; }) }` – dfsq Apr 14 '17 at 12:34
  • Simplified my code. I kept deferred but the promise now return the full device object because I'm not sure `/events` api returns the device ID. If this is the case then you're right, `deferred` can be removed ;) – Stephane Janicaud Apr 14 '17 at 12:38
  • Why downvote my answer ? Please provide arguments or a better answer... – Stephane Janicaud Apr 14 '17 at 12:43
  • The [`.success` method is deprecated and removed from AngularJS v1.6](http://stackoverflow.com/questions/35329384/why-are-angular-http-success-error-methods-deprecated-removed-from-v1-6/35331339#35331339). – georgeawg Apr 14 '17 at 12:44
  • See my answer for a solution without the use of deferred (deprecated) – known-as-bmf Apr 14 '17 at 12:50
  • Probably downvote for abusing deferred (known as deferred anti-pattern). You should have just returned object from then block. Plus deviceevents in this case response object. Btw, answer from @Julien is also incorrect for that reason. – dfsq Apr 14 '17 at 12:57
  • Ok guys, fixed ! – Stephane Janicaud Apr 14 '17 at 13:00
  • Thank @Julien for the edit request, I forgot this deferred var ;) approved ! – Stephane Janicaud Apr 14 '17 at 13:18
  • thank you @stej4n I'm getting a new error Cannot read property 'all' of undefined for using $q.all() . I inject $q in the controller like this : angular.module('myApp') .controller('DevicesCtr', [''$q', function ($q) {}]); – Taha Apr 14 '17 at 13:52
  • It should work, please post the full code of your controller so we can help – Stephane Janicaud Apr 14 '17 at 13:55
  • Answer completed – Stephane Janicaud Apr 14 '17 at 14:07
1

First of all: like Carnaru Valentin said, you should create a service to wrap your $http calls.

Secondly, I don't get your $http.get('events') call. You don't pass any parameters to it (deviceID or whatnot).

Does it return a list of all events for every devices ? For a specific device ?

If you just forgot to add a parameter to the query: here is a solution that could work:

var promises = response.map(function (device) {
  return $http.get('events/' + device.deviceID)
    .then(function (data) {
      return {
        device: device.deviceID,
        events: data
      };
    });
})

$q.all(promises)
  .then(function (devices) {
    $scope.myArrayofDevices = $scope.myArrayofDevices.concat(devices);
    // alternatively: $scope.myArrayofDevices = devices;
  });
known-as-bmf
  • 1,162
  • 8
  • 9
  • thank you for your help I get data perfectly from the server I put 'events' to simplify the code but my problem that in the final array some properties in objects inside the array are empty – Taha Apr 14 '17 at 13:16
  • You should try my or stej4n's solution ! `$q.all` will wait for all the promises to resolve and then return all the responses in an array. – known-as-bmf Apr 14 '17 at 13:19
0

Thing is you reassign $scope.myObject to a new object before callback is fired and assigned events to the old one. So both callback's assign properties to same object. You could just put all of the code in callback.

Anton Stepanenkov
  • 1,026
  • 8
  • 15
0
1. Create a service:

    function DataService($http, appEndpoint){
        return {
            getLists: getData
        }

        function getData(){
            return $http.get(appEndpoint + 'lists')
        }
      }

2. Create controller:

function ListsController(DataService){
   var self = this;
   self.data = null;
   DataService.then(function(response){
       self.data = response.data;
   });

   // Here manipulate response -> self.data;
}
Carnaru Valentin
  • 1,690
  • 17
  • 27