1

I have a custom directive which has got it's own scope which accepts values from the directive's DOM attributes but there are a few vars from the $scope which I want to access from the directive too. Can anyone help me to do this.

Here is my directive and how I use it.

appDirectives.directive('appTemplate', function () {
    return {
        restrict: 'E',
        templateUrl: 'partials/templates/template.html',
        scope: {
            template: '='
        },
    }
});
<div ng-repeat="template in templates" ng-click="chooseTemplate(template)">
    <app-template template="template"></app-template>
</div> 

And this is the template of the directive and here I have template value but I want also to access $scope.rootPath

<div class="template">
    {$ ???scope.rootPath??? $}
    {$ template is accesable $}    
</div> 
7
  • 1
    where do you plan on getting the value of rootPath? Is it an attribute, from a service, specific to the directive code, etc? Commented Mar 20, 2014 at 19:30
  • It's a constant global for the project and I am storing it in the $scope. Because of this I want to access it from the directive without the need to copy/paste it everywhere Commented Mar 20, 2014 at 19:34
  • which $scope is it in? I don't see it in your directive and since you've defined a scope in your return object you have created an isolate scope for this directive. You can expose it via a link function, but could you add the part of your code that accesses the rootPath property? Commented Mar 20, 2014 at 19:36
  • What is stopping you to pass rootPath as an attribute to the isolated scope of directive? scope: { template: '=', rootpath: '@' } inside directive. and then pass in the rootpath as attr where the directive is used? Commented Mar 20, 2014 at 19:38
  • @Matt Pileggi: rootPath is in the controllers scope but I am passing template value and making local scope for the directive. Maybe the link function will save me and I won't need this local scope.. Commented Mar 20, 2014 at 19:43

4 Answers 4

4

You can use is with isolated scopes as well:

appDirectives.directive('appTemplate', function () {
    return {
        restrict: 'E',
        templateUrl: 'partials/templates/template.html',
        scope: {
            template: '=',
            rootPath: '='
        },
    }
});
<div ng-repeat="template in templates" ng-click="chooseTemplate(template)">
    <app-template template="template" root-path="rootPath"></app-template>
</div> 

… and then access it as usual:

<div class="template">
    {$ rootPath is accesable $}
    {$ template is accesable $}    
</div> 

There are probably other solutions but this should work for you.

Sign up to request clarification or add additional context in comments.

Comments

1

The is exactly how you go about passing objects into a isolate scope. If your controller is in the parent of your directive then the directive will inherit the functionality of the controller.

Unless you need it to have an isolated scope, for example each template in templates has their own unique values then you can pass it in as an object like you are doing now.

Comments

1

It appears that you don't have to declare local scope for the directive, the attributes are accessible without it. After omitting the scope declaration it will work, and the directive will look like this:

appDirectives.directive('appTemplate', function () {
    return {
        restrict: 'E',
        templateUrl: 'partials/templates/template.html',
        transclude: true
    }
});

The other way, which will also work, is to inject the $scope.rootPath to the directive as a parameter.

1 Comment

Nice one. By the way - the "transclude: true" is not related to the fact that omitting the isolated scope will get you access to controller's scope. Regarding $rootScope inside the directive: it is possible and will work, but it is considered a bad practice.
1

Another option is to have appTemplate prototypally inherit from the parent scope and use $parse for the template attribute.

app.directive('appTemplate', ['$parse', function($parse) {
  return {
    restrict: 'E',
    templateUrl: 'template.html',
    link: function(scope, elem, attrs) {
      var templateGet = $parse(attrs.template);
      scope.$watch(templateGet, function(value) {
        scope.template = value;
      });
    }
  };
}]);

It sees all variables from the outtermost scope (templates, rootPath etc) but does not really depend on the name of the iteration variable in the ng-repeat. So both this:

<div ng-repeat="template in templates">
  <app-template template="template"></app-template>
</div>

and this:

<div ng-repeat="t in templates">
  <app-template template="t"></app-template>
</div>

works without any modification.

Caveats:

  1. If ng-repeat is defined as ng-repeat="t in templates" just because you already have a variable called template which is needed in the children scopes, you are effectively doomed because appTemplate overrides it internally (this does not affect parent variable, whatsoever)
  2. If appTemplate is meant to edit data that have been inherited, those data have to be at least a 2nd level property (customer.firstName, not firstName). This is a general caveat with scope inheritance.

Working plunker.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.