1

I've got a problem with assigning some properties to $scope.milestones object in my code.

MilestonesService.query({ gameId: $stateParams.gameId }, function(data) {
    $scope.milestones = data;
    for(var i in $scope.milestones) {
        if($scope.milestones[i]._id) {
            $http.get('/admin/tasks/byMilestone/' + $scope.milestones[i]._id).success(function(tasks) {
                $scope.milestones[i].tasks = tasks.length;
                $scope.milestones[i].tasksSolved = tasks.length;
                tasks.forEach(function(task) {
                    if(!task.evaluate.accepted) $scope.milestones[i].tasksSolved -= 1;
                }); 
            }).error(function(err) {
                console.log(err);
            });
        }
    }
});

It throws an error to console: Cannot assign to read only property 'tasks' of true, problem is on lines with $scope.milestones[i].tasks and $scope.milestones[i].tasksSolved. Why I can't assign value and extend each $scope.milestones object?

Edit: data

0: Resource
$$hashKey: "01J"
__v: 0
_id: "5664b44b4a502abc27613d7b"
assignedToGame: "5664a04eeff8972c24651371"
date: "2015-12-19T00:00:00.000Z"
description: "Haha"
solved: false
title: "Milestones works"
__proto__: Resource
$promise: Object
$resolved: true
length: 1
__proto__: Array[0]

$scope.milestones[i]:

$$hashKey: "01J"
__v: 0
_id: "5664b44b4a502abc27613d7b"
assignedToGame: "5664a04eeff8972c24651371"
date: "2015-12-19T00:00:00.000Z"
description: "Haha"
solved: false
title: "Milestones works"
__proto__: Resource
ketysek
  • 1,159
  • 1
  • 16
  • 46

2 Answers2

0

Replace with usual for

MilestonesService.query({ gameId: $stateParams.gameId }, function(data) {
    $scope.milestones = data;
    for(var i=0;i<$scope.milestones.length; i++) {
        if($scope.milestones[i]._id) {
            $http.get('/admin/tasks/byMilestone/' + $scope.milestones[i]._id).success(function(tasks) {
                $scope.milestones[i].tasks = tasks.length;
                $scope.milestones[i].tasksSolved = tasks.length;
                tasks.forEach(function(task) {
                    if(!task.evaluate.accepted) $scope.milestones[i].tasksSolved -= 1;
                }); 
            }).error(function(err) {
                console.log(err);
            });
        }
    }
});

or use underscore forEach:

MilestonesService.query({ gameId: $stateParams.gameId }, function(data) {
    $scope.milestones = data;
    _.forEach(function(milestone){
        if(milestone._id) {
            $http.get('/admin/tasks/byMilestone/' + milestone._id).success(function(tasks) {
                milestone.tasks = tasks.length;
                milestone.tasksSolved = tasks.length;
                tasks.forEach(function(task) {
                    if(!task.evaluate.accepted) milestone.tasksSolved -= 1;
                }); 
            }).error(function(err) {
                console.log(err);
            });
        }
    });
});
Alexander Vasilyev
  • 1,273
  • 2
  • 15
  • 22
0

As you can see, the data object is not an array but an array-like javascript object with some additional properties, so for(var i in $scope.milestones) { will iterate over the object properties of scope.milestones, and will eventually reach milestones.$resolved (===true), which is a boolean, so trying to access a member of it will throw the error in the question. However if it was an array it would be still a bad practice to iterate over array indices with for..in.

For a quick workaround, you can change the for..in to :

for(var i = 0; i < $scope.milestones.length; i++) {

or use Array.prototype.forEach.call:

Array.prototype.forEach.call($scope.milestones, function(item) {
    if(item._id) {
        $http.get('/admin/tasks/byMilestone/' + item._id).success(function(tasks) {
            item.tasks = tasks.length;
            item.tasksSolved = tasks.length;
            tasks.forEach(function(task) {
                if(!task.evaluate.accepted) item.tasksSolved -= 1;
            }); 
        }).error(function(err) {
            console.log(err);
        });
    }
});
Community
  • 1
  • 1
Tamas Hegedus
  • 28,755
  • 12
  • 63
  • 97