1

All, I have the following AngularJS below. Why is $scope.gotData not visible outside of the call to getData.success()? Note that $scope.gotData is visible to the view: I can display the value of scope.gotData by placing {{gotData}} within my index.html.

Why can I not access $scope.gotData as a variable elsewhere in my controller? This is a question concerning the details of $scope.

getData.js

myApp.factory('getData',function($http){
return $http.jsonp('https://foo.com/bar.json')
       .success(function(data){
            return data;
        })
        .error(function(err){
            return err;
        });
});

MainController.js

myApp.controller('MainController', ['$scope','getData', function($scope, getData){
    getData.success(function(data){
        $scope.gotData = data;
    });

    $scope.gotData /* NOT DEFINED HERE */
   }]);

index.html

<html>
  <head>
    <script src="js/vendor/angular.js"></src>
  </head>
  <body ng-app="MyApp">
    <div ng-controller="MainController">
      {{gotData}} /* I CAN SEE THE DATA HERE */
     </div>
  </body>
</html>

3 Answers 3

4

the call to getData.success is asynchronous. So before executing that success function, your call to console of $scope.gotData is done. So you are supposed to define a default value of this $scope.gotData beforehand. And when you get a success call, only then you should use it. Something like this :

myApp.controller('MainController', ['$scope','getData', function($scope,getData){

    $scope.gotData = null;

    getData.success(function(data){
        $scope.gotData = data;
    });

    if($scope.gotData != null) 
        // Do something useful with this data
}]);
Sign up to request clarification or add additional context in comments.

2 Comments

So, does this mean that once the data has been retrieved that $scope.gotData is then defined? If the server responds fairly quickly then I should be able to setTimeout(console.log($scope.gotData),1000) outside of the call to getData.success to see the data, right?
Yes..You'd be able to see the data if you use setTimeout(or $timeout service if you want to do thing more angular way). Provided you get the data within 1 second(1000 milliseconds)
1

The reason why you cannot see $scope.gotData outside the getData.success() function is because .success() is async and the value is not available when you try to access it outside .success(). This essentially means that the promise has not been resolved yet.

Moreover, once angular's digest cycle identifies that $scope.gotData is populated, it quickly updates the view. Thats the reason why you can see $scope.gotData in the view

Things would be more clear once you put a watch on $scope.gotData

 myApp.controller('MainController', ['$watch','$scope','getData', function($watch,$scope, getData){
     getData.success(function(data){
        $scope.gotData = data;
     });

    $scope.$watch($scope.gotData,function(n,o){
       console.log("new val-> "+n);
       console.log("old val->"+o);
     })   
 }]);

3 Comments

So, the promise is only resolved when getData.success is called from the controller? I want to understand the "digest cycle" and these "promises" ($q). Do you have a good layman's resource for understanding what Angular is doing in the background?
Well, yea. When the promise is resolved, .success is called, and when it is rejected, .error is called. You can get a better idea on promises from this link. Also, this and this are nice places to get started with $q. Here's the official docs on $q
I'll read those. I had already found the official documentation but the Angular API can be pretty opaque if you don't have a background in computer science. I'm reading on the $watch service right now. This site is pretty good.
0

Although not the best programming practice, but a solution to this is to use $rootScope.

myApp.controller('MainController', ['$scope','getData', function($scope, getData){
    getData.success(function(data){
        $rootScope.gotData = data;
    });

    console.log($rootScope.gotData) // this will be accessible across
                                    // different controllers aswell
   }]);

1 Comment

Thanks, Asad. I'm going to avoid using $rootScope. That's playing with fire.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.