In AngularJS, my directive can't access $scope properties of the parent controler defined in $http

I'm creating a custom directive that inherits the scope of the parent controller. For the most part, I can access the directive's "scope" object that I set in the controller's "$scope" except for properties I set inside an $http.get. Whether those properties came from the API or were just literally defined does not matter.

What's very weird to me is that if I just log the directive's "scope" I can definitely see the properties set by $http.get, but if I try to access them directly they are undefined.

I can access everything in the HTML view perfectly.

var myApp = angular.module('myApp');

myApp.controller('getData', function($scope, $http) {
  var myData='myData.json';
  $scope.helloFromController = "Hello! This is the controller!";
  $scope.getTheData = function() {
    $http.get(myData).
      success(function(data, status) {
        $scope.helloFromHttp = "Hello! This is the http!";
      });
  };
  $scope.getTheData();
});

myApp.directive('useData', function ($parse) {
  var directiveObj = {
    link: function (scope, element, attrs) {
      console.log(scope); 
        // Returns the scope object that clearly includes the helloFromController and helloFromControllerHttp properties
      console.log(scope.helloFromController); 
        // returns "Hello! This is the controller!"
      console.log(scope.helloFromHttp) 
        // returns undefined
    } 
  };
  return directiveObj;
});

It looks like there's something about how $scope works with $http that I don't understand. Help is appreciated.


ANSWERS:


The linking function executes before the callback from the asynchronous http call gets invoked.

Sample code:

<div ng-controller="MyCtrl" use-data>
  Hello, {{ userData.username }}!
</div>


var myApp = angular.module('myApp', []);

myApp.controller('MyCtrl', function($scope, $http) {

  function getTheData() {
    $http.get("http://jsonplaceholder.typicode.com/users/1").
    success(function(response, status) {
      $scope.userData = response;
    });
  };

  getTheData();
});

myApp.directive('useData', function($parse) {
  return {
    link: function(scope, element, attrs) {
      scope.$watch("userData", function(newValue, oldValue) {
        console.log(newValue, oldValue);
      });
    },
    restrict: "A"
  };
});

Your directive is sharing the same scope of the controller. Your directive's link function loads when the directive is found in your template. $scope.helloFromController is just a string. So, you are seeing this by logging in console. But, $scope.helloFromHttp is set after the promise is resolved for $http. So, you don't see the value instantly as console.log(scope.helloFromHttp) before it is set in the controller. You can try using $timeout to see the changed value of scope.helloFromHttp.

myApp.directive('useData', function ($parse, $timeout) {
  var directiveObj = {
    link: function (scope, element, attrs) {
      // Returns the scope object that clearly includes the helloFromController and helloFromControllerHttp properties
      console.log(scope); 

      // returns "Hello! This is the controller!"  
      console.log(scope.helloFromController); 

      // returns undefined
      console.log(scope.helloFromHttp) 

      // set $timeout to trigger after 10 sec, you can reduce or increase the time
      $timeout(function() {
        console.log(scope.helloFromHttp); 
      }, 10000)
    } 
  };
  return directiveObj;
});

Hope, this helps.


Actually your code works fine without any changes; the problem is that you displayed it in the console, but if you display it in HTML, it gets refresh as expected. Here's the example:

directive('useData', function($parse) {
  return {
    template: "From directive: {{helloFromHttp}}",
    link: function(scope, element, attrs) {

      console.log(scope);
      // Returns the scope object that clearly includes the helloFromController and helloFromControllerHttp properties
      console.log(scope.helloFromController);
      // returns "Hello! This is the controller!"
      console.log(scope.helloFromHttp);
      // returns undefined
    }
  };
});


 MORE:


 ? Angular.js - $http.get - use cache from file
 ? Referencing multiple API calls in one Service (Angular)
 ? In AngularJS, $http doesn't change my select option tag data
 ? Custom infinite scrolling trigger many times
 ? Using the $q service with angular
 ? AngularJS TypeError: "track" is not a function
 ? NodeJS rest api with mysql cannot iterate on the output format
 ? Having a hard time making a post request to a JSON file using angular
 ? Angular $http not handling error
 ? How can I change the structure of an AngularJS get request?