4
votes

Preface

When I declare a directive under a controller, e.g.

<div ng-controller="MyController">
  <my-directive></my-directive>
</div>

the directive inherits that controller's scope by default. This means if the controller defines

$scope.Heaven = "Free Beer"

then I have access to that within the directive's template via

{{ Heaven }}

Question

When declaring a directive within another directive, why doesn't the child inherit scope like it would if placed in a controller?

<my-parent-directive>
  <my-child-directive>
  </my-child-directive>
</my-parent-directive>

In short, if I declare a controller function for my-parent-directive and in it write:

$scope.Heaven = "Free Beer"

My child directive doesn't have access to this by default. Why is that? (This assumes "scope: true" within the parent, no scope declaration in the child, and the child requiring the parent via "require: 'my-parent-directive')

Example codepens:

Directive wrapped in controller
Directive wrapped in directive

Question was modified after answer was given - the below is to preserve the reference
Directive wrapped in directive old

1
it does if you try it with $scope.abc.Heavenharishr
How would I access that in the child directive?aaaaaa
{{abc.Heaven}}, just like every other variableharishr
Oh you mean like this? codepen.io/anon/pen/gbPLZY?editors=101 Because that doesn't workaaaaaa

1 Answers

5
votes

I am looking at the "Directive wrapped in directive old" on codepen. I think it is this you want to fix, but I'm not certain since your codepen is different to the example in your question (that's not a criticism, just clarification in case I am heading down the wrong route for you!)

However, if I am correct (and I am referring to the "Directive wrapped in directive old" on codepen for the rest of this answer):

You have declared the scope in myWrapper to be inherited ("scope: true"), therefore any properties that you add to the scope within myWrapper (such as "$scope.passdown = $attrs.passdown;") will only be visible to myWrapper.

You can remove the "scope: true" from myWrapper to share the scope between everything (not a great structure to use, but it will work) and you will solve your immediate problem, if I have understood you correctly. Or you can move the "passdown" property to a mutable object on the "parent" controller "$scope.abc = {passdown: ''};" for example. Then modify the value in myWrapper: "$scope.abc.passdown = $attrs.passdown;" and access it as "abc.passdown" in your interpolated expressions.

a bit of background:

changes to immutable types in "child" controllers/directive will make a copy of the property and those changes will never be seen on any other scope.

No scope declaration means shared scope - all components that share this scope too can see any properties / changes (to mutables) made on the scope. Tends to end up with closely coupled components that become very difficult to maintain.

"scope: true" means inherited scope and any additions made to the scope will only be visible to the inherting scope (ie the "child"). Changes to mutable properties in the parent will be visible to all other components that share this scope.

"scope: {...}" creates an isolated scope and provides a safe way to expose properties to parents and let the children modify those properties. This implementation is more work but you will end up with code that is easier to understand, maintain and share.

I hope this answer isn't too rambling and it helps you solve your problem.