Angularjs - $rootScope in directive link function

88,725

Solution 1

From my experiments \ experience, it seems that since all $scopes ultimately inherit from the $rootScope you will be able to access data on it without requesting it as a service, following standard javascript prototypical inheritance rules. If you were to set the scope property in your directive to false or {} you will find that you can no longer access it.

.directive("myBar", function($rootScope) {
    return {
        restrict: "E",
        scope: { /* Isolate scope, no $rootScope access anymore */ },
        transclude: true,
        replace: true,
        template: '<div>' + 
                  '<span ng-transclude></span>' + 
                  '{{rsLabels.welcome}} {{rsUser.firstName}}!' + 
                  '</div>'
    };
});

Example: http://jsbin.com/bequy/1/edit

Solution 2

You can do this way:

{{$root.rsLabels.welcome}}

Solution 3

It's not recommended to use the root scope to set and get properties in your angular application. Try using the $cacheFactory, since that way you can also cache some values over various requests. ($cacheFactory docs)

Solution 4

Sometimes I have to use $scope.$root:

app.directive('setOrdinal', function() {
  return {
    link: function($scope, $element, $attr) {

      var steps = $scope.$root.steps;

      $scope.$watch(setOrdinal, function(value) {
        if (value)
        {
          // steps code here
        }
      });
    }
  };
});

app.controller('stepController', ['$scope', '$rootScope', 'GetSteps', function ($scope, $rootScope, GetSteps) {
  var s = $scope;
  var r = $rootScope;

  s.initialize = function(id)
  {
    GetSteps.get({id: id}, function(resp){
      r.steps = resp.steps;
    });
  };
}]);

Solution 5

After laboring away on this same question for quite some time, I thought it was worth noting something that was neglected in the first post. Here is my original code:

app.directive('countrymap', function() 
{
    return {
        link: function(scope, element, attrs) {
            scope.$watch("countryMap", function (newCountry, oldCountry) 
            {
                setTimeout( function() 
                {
                    //function body here    
                }, 100);
            })
        }
    };  
}]);

Aside from the more philosophical design question of whether or not you should even use $rootScope at all, there is one blatantly wrong thing with my code above that I feel was left out from Mike's solution - the reference to $rootScope. If you're like me and have segregated your directive and controller files you will need to modify your code as follows:

app.directive('countrymap', ['$rootScope', function($rootScope) 
{
    return {
        link: function(scope, element, attrs) {
            $rootScope.$watch("countryMap", function (newCountry, oldCountry) 
            {
                setTimeout( function() 
                { 
                    //function body here
                }, 100);
            })
        }
    };  
}]);

Yet, there is still one more nagging question: can I accomplish the same goal without referencing $rootScope in the directive? Indeed you can. You need to broadcast the change to the $rootScope property effectively letting all child scopes know about the change and watching for this change in the directive.

Controller:

$rootScope.countryMap = 'thiscountry_map';
$rootScope.$broadcast( "countryMapChanged", $rootScope.countryMap );

Directive:

app.directive('countrymapalt', [function() 
{
    return {
        link: function(scope, element, attrs) {
            scope.$on("countryMapChanged", function(event, map) 
            {
                setTimeout( function() 
                { 
                    //function body here
                }, 100);
            })
        }
    };  
}]);
Share:
88,725

Related videos on Youtube

GRowing
Author by

GRowing

Every time I find help in your answers I am endlessly thankful. I hope to give back with my insights and code as much as I receive.

Updated on September 06, 2020

Comments

  • GRowing
    GRowing over 3 years

    I am asking this question because I am not quite clear on how to think of rootscope as a dependency passed to directives

    I have a directive that needs to display some information from $rootScope ...

    I thought I needed to pass the $rootScope to a directive but when I write a directive like this it seems to work.

    .directive("myBar", function () {
     return {
        restrict: "E",
        transclude: true,
        replace: true,
        template:   '<div>' + 
                    '<span ng-transclude></span>' + 
                    '{{rsLabels.welcome}} {{rsUser.firstName}}!' + 
                    '</div>'
    }
    })
    

    When do I need to do this?

    .directive("myBar", function ($rootScope) {
     return {
        restrict: "E",
        transclude: true,
        replace: true,
        template:   '<div>' + 
                    '<span ng-transclude></span>' + 
                    '{{rsLabels.welcome}} {{rsUser.firstName}}!' + 
                    '</div>'
    }
    })
    

    Can I and HOW do I use rootScope if I need it in the link function of the directive - or should I do it in the controller of the directive?

    .directive("myBar", function ($rootScope) {
     return {
        restrict: "E",
        transclude: true,
        replace: true,
        link: function (scope, element, attrs, rootScope) {
            rootScope.rsUser = { firstName: 'Joe' };
            rootScope.rsUser = { welcome: 'Welcome' };
        },
        template:   '<div>' + 
                    '<span ng-transclude></span>' + 
                    '{{rsLabels.welcome}} {{rsUser.firstName}}!' + 
                    '</div>'
    }
    })
    

    My rootScope data is defined in run function

     .run(function ($rootScope) {
    
      $rootScope.rsLabels = { 
          welcome: 'Welcome'
      };
    
      $rootScope.rsUser = { 
         firstName: 'Joe'
      };
    });
    

    Thank you!

  • GRowing
    GRowing about 10 years
    Yes, I figured using $rootScope like this is not the best of ideas. Thanks for the suggestion btw. I am looking for better ways to create widely accessible objects that I can use site wide from various directives though. I find that documentation on angular site is completely useless (like much of that site) because it neither explains anything not demonstrates real use case or at least logical use cases. In my case all directives across the site must have access to user information,,, and a few other bits of information, at all times. Best way? Do you know of useful. good documentation maybe?
  • GRowing
    GRowing about 10 years
    ah! I understand. As Kurt pointed out it is not the best way to set properties of the app in angular but I needed to understand the rootScope and this explains it better. Thank you. Do you happen t know how $root scope is to be accessed in the link function of the directive?
  • GRowing
    GRowing about 10 years
    Hey, I found some good info around plus this jmdobry.github.io/angular-cache/guide.html, and a useful YT video .. Thanks for this tip! I appreciate it a lot :) and I think I will look deeper into it as an actual use approach in what I am working on. Mike however did address my question with an explanation so I will mark his answer as the correct answer.
  • Mike Cheel
    Mike Cheel about 10 years
    You need to think of $rootScope as being the global namespace and you want to avoid cluttering it. You can inject it in your directive but the whole point of directives is to be a component without too many outside dependencies. If you need something from $rootScope you might consider refactoring it into a service.
  • GRowing
    GRowing about 10 years
    It makes sense. I suppose I was resorting to using any kin dof equivalent to globals on account of having to make data x available at all times and not knowing how else to approach it. I DO use localStorage for some stuff but now looking at cacheFactory and the extended version of it,, and how they use localstorage, I am seeing the light. Thanks!
  • ivkremer
    ivkremer over 9 years
    Thanks, didn't that. I use link: function(scope, ...) { scope.$root } to access $rootScope from a directive.
  • ivkremer
    ivkremer over 9 years
    Yeah, I mean I was googling for accessing the $rootScope from directive and I didn't know about the $root property. Thanks for the answer.
  • Mike Cheel
    Mike Cheel almost 9 years
    Setting scope: true will make it work. By setting it to an empty hash {} or false isolates the scope and breaks the inheritance chain. (See Directive Definition Object, scope) code.angularjs.org/1.4.1/docs/api/ng/service/$compile (my example is against 1.2.1 but it hasn't changed from what I can tell).
  • GOSCHEN
    GOSCHEN almost 8 years
    Should be the correct answer... Thanks, anyway for providing your solution.
  • EmptyData
    EmptyData almost 7 years
    saved my lots of time
  • a2f0
    a2f0 over 6 years
    Solid solution. A+