9

Let's say I'm loading a variable into $scope with $http:

$http.get('/teachers/4').success(function(data){
  $scope.teacher = data;
});

My template uses this data:

Teacher: {{teacher.name}}
<students-view students="teacher.students"></students-view>

This directive can load BEFORE teacher finishes loading, but my directive has code that depends on the teacher.students array being loaded:

app.directive('studentsView', function(){
  return {
    scope: { students: '=' },
    controller: function($scope){
      _.each($scope.students, function(s){
        // this is not called if teacher loads after this directive
      });
    }
  };
});

How do I get the behavior that I want here? I don't want to stop using $http, and I would like to not have to assign a promise to the scope if possible.

1
  • what is happening in the loop? Can put that loop inside the success callback in controller if that helps or move the whole request to a service Commented Dec 19, 2014 at 0:00

2 Answers 2

21

Use a watch to wait for students to be available. Once it's available you call the code that depends on it, then remove the watch. You can skip removing the watch if you want the code to execute every time students changes.

app.directive('studentsView', function(){
  return {
    scope: { students: '=' },
    link: function($scope){
      var unwatch = $scope.$watch('students', function(newVal, oldVal){
        // or $watchCollection if students is an array
        if (newVal) {
          init();
          // remove the watcher
          unwatch();
        }
      });

      function init(){
        _.each($scope.students, function(s){
          // do stuff
        });
      }
    }
  };
});
Sign up to request clarification or add additional context in comments.

2 Comments

What's the difference between putting this code in the controller function, and putting it into the link function?
@Dave In the DOM compilation process, directive controllers get instantiated before link functions, so the link functions can essentially be seen acting on the end/stable state. The Angular docs recommend using controller when you want to expose an API to other directives. Otherwise use link. Some argue otherwise: Difference between the 'controller', 'link' and 'compile' functions when defining a directive. It just depends on whether the aforementioned ordering matters to your use case.
3

You'll probably need to do some kind of watch on students to know when it is updated, then run your _.each when the watch is triggered:

app.directive('studentsView', function(){
  return {
    scope: { students: '=' },
    controller: function($scope){
      scope.$watch('students', function(newValue, oldValue) {
        _.each($scope.students, function(s){
          // this is not called if teacher loads after this directive
        });     
      };
    }
  };
});

More on $watch: https://docs.angularjs.org/api/ng/type/$rootScope.Scope

Comments

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.