31

How can I ensure that data from a controller has been loaded in a directive before the link function is run?

Using psuedo-code, I could have:

<my-map id="map-canvas" class="map-canvas"></my-map>

for my html.

In my directive I might have something like this:

app.directive('myMap', [function() {



return{
    restrict: 'AE',
    template: '<div></div>',
    replace: true,
    controller: function ($scope, PathService) {

        $scope.paths = [];

        PathService.getPaths().then(function(data){
            $scope.paths = data;

        });

    },
    link: function(scope, element, attrs){
        console.log($scope.paths.length);

    }

}


}]);

The above won't work because console.log($scope.paths.length); will get called before the service has returned any data.

I know I can call the service from the link function but would like to know if there is a way to "wait" for the service call before firing the link function.

3
  • maybe you can use an event in your service. (i do the same for some visual access restrictions) just use $scope.$on("service-event", ... in your directive and in your service $rootScope.$broadcast("service-event", payload); Commented Dec 15, 2014 at 14:21
  • 1
    Have a scope.$watch('paths' in the link function to see when the that variable gets data. Commented Dec 15, 2014 at 14:21
  • Will try stackoverflow.com/questions/12497590/… Commented Dec 15, 2014 at 14:22

2 Answers 2

48

The easiest solution would be to use ng-if since the element and directive would be rendered only when the ng-if is resolved as true

<my-map id="map-canvas" class="map-canvas" ng-if="dataHasLoaded"></my-map>

app.controller('MyCtrl', function($scope, service){
  $scope.dataHasLoaded = false;

  service.loadData().then(
    function (data) {
      //doSomethingAmazing
      $scope.dataHasLoaded = true
    }
  )
})

or use promises

return {
  restrict: 'AE',
  template: '<div></div>',
  replace: true,
  controller: function ($scope, PathService) {
    $scope.paths = [];
    $scope.servicePromise = PathService.getPaths()
  },
  link: function (scope, element, attrs) {
    scope.servicePromise.then(function (data) {
      scope.paths = data;
      console.log(scope.paths)
    });
  }
}
Sign up to request clarification or add additional context in comments.

6 Comments

The directive and controller would not be created if used with falsy ng-if but if the data you are loading is used by the directive and not required in controller it would make sense to use it link/controller of the directive
This is not working. The ng-if statement is removing the my-map tag from the dom and the controller is never firing.
I tried using a controller that was not based in the directive and it still is not working. This must be a solution for <1.2.0.
James as I said if you use ng-if then directive and controller will not be created, but if you are using the data only in this directive you can omit ng-if and load data inside directive's controller
Ok, I see. I'll mark it as correct as it is close enough to what I need. Thank you for your help.
|
1
app.directive('MyDirective', function() {
    return {
        controller: function() {
            this.$postLink = function() {
            // here will run after the link function,
            // and also after the binding came in
            };
        },
        controllerAs: 'vm'
    };
});

check out the angular 1.5 Components have a well-defined lifecycle and it works on directives to

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.