javascriptangularjsrestiterationangularjs-ng-resource

Access propertyname while looping through an object


As you can see in the code I provided in this question, I try to loop over the properties of an object. All properties are empty objects! I also have another object where I stored a couple of rest-calls (ngResource Stuff which is not important for this question).

Here you can see the "Rest-Calls" stored in $scope.restCalls.

$scope.restCalls = [
   {
     resource1: RestService.call1,
     resource2: RestService.call2,
     resource3: RestService.call3
   },
   {
     resource4: RestService.call4,
     resource5: RestService.call5,
     resource6: RestService.call6
   },
   {
     resource7: RestService.call7,
     resource8: RestService.call8,
     resource9: RestService.call9
   }
];

$scope.data symbolizes the data for each tab. Every object in this array holds the data for the tab. All resources are initilized empty and if the user changes to a page the resources will get stored here.

$scope.data = [
   {
     resource1: {},
     resource2: {},
     resource3: {}
   },
   {
     resource4: {},
     resource5: {},
     resource6: {}
   },
   {
     resource4: {},
     resource5: {},
     resource6: {}
   }
];

So far so good. I gurantee that the calls are working fine. In my application there are multiple tabs and so I want to try to implement some lazy loading :D

Therefore I implemented a function:(the index is defined in the html and is only the a number between 0 and 2)

<uib-tab heading="Tab1" select="tabChange(0)">
... HERE I have some tables which access the $scope.data[0] data
</uib-tab>
<uib-tab heading="Tab2" select="tabChange(1)">
... HERE I have some tables which access the $scope.data[1] data
</uib-tab>
<uib-tab heading="Tab3" select="tabChange(2)">
... HERE I have some tables which access the $scope.data[2] data
</uib-tab>

Here you can see the function:

$scope.tabChange = function (index) {
        for (var propertyName in $scope.data[index]) {
            $scope.restCalls[index][propertyName]().$promise.then(function (data) {
                $scope.data[index][propertyName] = data;
            });
        }
    };

Now lets come to the problem description:

The results only get stored into the wrong property of $scope.data[index]. Its always the last propertyname. So for example I change to tab2(index 1). $scope.data will end up like this:

$scope.data = [
   {
     resource1: {},
     resource2: {},
     resource3: {}
   },
   {
     resource4: {},
     resource5: {},
     resource6: RESULT OBJECT OF THE LAST REST CALL!
   },
   {
     resource7: {},
     resource8: {},
     resource9: {}
   }
]; 

I think that propertyname is not available in the then function. But I have no clue how to get the name into this function.


Solution

  • The problem arises because the propertyName is in the upper scope of the function and its value is changed before the function is called. You can bind your variable to function scope like below.

    $scope.tabChange = function (index) {
            for (var propertyName in $scope.data[index]) {
                $scope.restCalls[index][propertyName]().$promise.then(function (propertyName,data) {
                    $scope.data[index][propertyName] = data;
                }.bind(null,propertyName));
            }
        };
    

    You can learn more about javascript closures here and in other sources you can find from Google.