Wait for data in controller before link function is run in AngularJS directive

26,195

Solution 1

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)
    });
  }
}

Solution 2

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

Share:
26,195
James Satori-Brunet
Author by

James Satori-Brunet

Updated on January 27, 2022

Comments

  • James Satori-Brunet
    James Satori-Brunet over 2 years

    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.

  • maurycy
    maurycy over 9 years
    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
  • James Satori-Brunet
    James Satori-Brunet over 9 years
    This is not working. The ng-if statement is removing the my-map tag from the dom and the controller is never firing.
  • James Satori-Brunet
    James Satori-Brunet over 9 years
    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.
  • maurycy
    maurycy over 9 years
    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
  • James Satori-Brunet
    James Satori-Brunet over 9 years
    Ok, I see. I'll mark it as correct as it is close enough to what I need. Thank you for your help.
  • Undefitied
    Undefitied over 7 years
    Note that ng-if runs on each scope digest