4

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

John Slegers
  • 45,213
  • 22
  • 199
  • 169
aaaaaa
  • 1,233
  • 13
  • 24
  • it does if you try it with `$scope.abc.Heaven` – harishr Dec 06 '14 at 17:29
  • How would I access that in the child directive? – aaaaaa Dec 06 '14 at 17:34
  • `{{abc.Heaven}}`, just like every other variable – harishr Dec 06 '14 at 17:39
  • Oh you mean like this? http://codepen.io/anon/pen/gbPLZY?editors=101 Because that doesn't work – aaaaaa Dec 06 '14 at 17:41
  • possible duplicate of [Access Parent Scope in Transcluded Directive](http://stackoverflow.com/questions/16866749/access-parent-scope-in-transcluded-directive) – aaaaaa Dec 06 '14 at 18:01
  • This question isn't really about transclusion - it seems to be about access to $scope properties depending on the "scope: " value of a directive declaration object. That isn't to say that the question referred to above doesn't answer this question! – lukkea Dec 06 '14 at 18:06
  • @harish you are on the right lines, in that declaring "Heaven" within a js object will make it mutable and solve one of the problems here, but that solution still leaves the problem that the scope is inherited and therefore the property needs to also be moved (to the "parent" controller) for your suggestion to work. – lukkea Dec 06 '14 at 18:16

1 Answers1

5

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.

lukkea
  • 3,606
  • 2
  • 37
  • 51
  • Totally agree , the demo and question should have same code! Issue gets all muddled up discussing totally different variables – charlietfl Dec 06 '14 at 18:04
  • 1
    Yeah - Apparently my google keywords were lacking, because the root of my problem is that "transclusion: true" and "scope: true" both create their own scopes (according to http://stackoverflow.com/a/16868935/984407) I didn't realize that and now I'm starting to understand my issue a little more. What you say makes more sense to me after reading that answer, and I appreciate your 'background' section because I'm really having trouble learning this stuff. – aaaaaa Dec 06 '14 at 18:07
  • That's great - glad I could help. Post some more questions here if you want to know more. Just remember that scope has three "states": shared, inherited and isolated. Once you've got those straight you should be good on this point, I think. – lukkea Dec 06 '14 at 18:08
  • @charlietfl - I apologize for that, I'll fix it now. Basically I have to remove the parent controller, but I thought the concepts were the same – aaaaaa Dec 06 '14 at 18:08
  • @PhilOlson your question should be self contained, then any demo should be a representation of the question – charlietfl Dec 06 '14 at 18:10
  • Phil - it would be great if you could change your question to match the codepen I have referred to; if I am on the right lines at least, then I won't have to change my answer! – lukkea Dec 06 '14 at 18:10
  • @charlietfl - understood. @ lukkea - I'll comment when it's finished – aaaaaa Dec 06 '14 at 18:18
  • @lukkea - I kept a reference to the old link – aaaaaa Dec 06 '14 at 18:39