Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Isolated scope not isolated #7716

Closed
TheManFran opened this issue Jun 5, 2014 · 9 comments
Closed

Isolated scope not isolated #7716

TheManFran opened this issue Jun 5, 2014 · 9 comments

Comments

@TheManFran
Copy link

I was following the dev guide (https://docs.angularjs.org/guide/directive) on isolated scope and was not experiencing the described behaviour. The section that describes the behaviour of the transclude option mentioned that if the transclude wasn't included the expression would have resolved to the isolated scope value, in this case the name 'Jeff'. I didn't experience this behaviour, as the binding was made to the external scope.

I realized this has changed between version 1.0.8 (http://jsfiddle.net/TheManFran/wqSeJ/1/) and version 1.2.0 (http://jsfiddle.net/TheManFran/CbLcw/1/). I can't find any documentation that explains this change.

To me this feels like a bug as one expects the bindings with isolated scope not to bind to the external scope.

@caitp
Copy link
Contributor

caitp commented Jun 5, 2014

The section that describes the behaviour of the transclude option mentioned that if the transclude wasn't included the expression would have resolved to the isolated scope value, in this case the name 'Jeff'.

Where does it say that?

What is happening is, transclude: true tells the compiler to collect the child nodes of the directive, compile them, and pass their link function (essentially) to the directive's link routine and controller. the ng-transclude directive handles the transclude function, and doesn't pass a scope parameter. The transclude function, if not passed a scope, is instead given a new scope, a child of the parent scope. That logic can be seen at https://github.com/angular/angular.js/blob/master/src/ng/compile.js#L988-L1002

So it's basically doing exactly what you'd expect it to --- the transcluded content is linked against a new child of the isolate scope directive's parent. You can get different behaviour if you call the transclude function manually, rather than relying on ng-transclude.

Anyways, as for documentation regarding that change, the place you want to look is CHANGELOG.md --- In particular, this line from 1.2.0:

@TheManFran
Copy link
Author

Hi

Below is the extract from the documentation. What this tells me is that if the transclude option isn't set the {{name}} expression would be bound against the isolated scope, but (please see the fiddles from the original comment) that behaviour has changed in 1.2.0. It now seems that the isolated scope is not truly isolated. The behaviour is as expected when transclude is set to true, but when the transclude, and ng-transclude is removed it makes sense to bind to isolated scope, which happened in 1.0.8, but not in 1.2.0

Ordinarily, we would expect that {{name}} would be Jeff. However, we see in this example that the {{name}} binding is still Tobias.

The transclude option changes the way scopes are nested. It makes it so that the contents of a transcluded directive have whatever scope is outside the directive, rather than whatever scope is on the inside. In doing so, it gives the contents access to the outside scope.

Note that if the directive did not create its own scope, then scope in scope.name = 'Jeff'; would reference the outside scope and we would see Jeff in the output.

This behavior makes sense for a directive that wraps some content, because otherwise you'd have to pass in each model you wanted to use separately. If you have to pass in each model that you want to use, then you can't really have arbitrary contents, can you?

@caitp
Copy link
Contributor

caitp commented Jun 5, 2014

You would "expect" that {{name}} would be Jeff, because you "expect" that the child nodes use the same scope as the isolate scoped directive.

However, this is not the case since 909cabd (1.2.0) --- with the exception of when you explicitly link the transcluded content against the isolate scope (http://jsfiddle.net/ajwQR/)

Basically, isolate scopes were broken pre-1.2.0, and have since become unbroken. At least as far as their "isolated" property is concerned.

@petebacondarwin
Copy link
Contributor

I think that excerpt is actually talking about the fact that if the isolate scope was not there then you would get a different result.

Perhaps the bit about transclude is worded poorly as it seems to imply that the "original contents" of the element containing the directive will be bound differently based on whether we use transclude or not.

But this is not the case.

  • Children of an element are always bound to the scope of the element at the point it appears (let's call it outerScope).
  • If you have isolated scope then the scope on any template for that directive (and the scope available in the link function) (let's call that directiveScope) is isolated from the outerScope.
  • If you have a template then this will replace the contents of the element that has the directive.
  • If you have a template and don't use transclusion then this original content is lost
  • If you have a template and do use transclusion then you can inject this original content (effectively bound to the outerScope) into the template, where everything else is bound to the directiveScope, which may be isolated.

@caitp
Copy link
Contributor

caitp commented Jun 5, 2014

If you have a template and do use transclusion then you can inject this original content (effectively bound to the outerScope) into the template, where everything else is bound to the directiveScope, which may be isolated.

If you have a template and do use transclusion, then you can inject this original content effectively bound to whichever scope you want it to be bound to, but if you do not give it a specific scope, or use the ng-transclude directive to handle this injection for you, then it will use a child of the original scope.

@caitp
Copy link
Contributor

caitp commented Jun 5, 2014

Oh, and having a template is not actually necessary at all, it turns out. You can transclude content regardless -- although I couldn't explain why we let you do that without a template :>

@TheManFran
Copy link
Author

Sweet I understand the isolation now. I think the wording in the doc could
just be made clearer. Is see that if you create a child scope (scope:true)
it works like I expected.

Thanks.

On Thu, Jun 5, 2014 at 9:16 PM, Caitlin Potter [email protected]
wrote:

Oh, and having a template is not actually necessary at all, it turns out.
You can transclude content regardless


Reply to this email directly or view it on GitHub
#7716 (comment).

@Narretz
Copy link
Contributor

Narretz commented Jun 20, 2014

@TheManFran I seems like this issue is resolved, so I'm going to close it. Feel free to reopen it if there's more to it.

@Narretz Narretz closed this as completed Jun 20, 2014
@TheManFran
Copy link
Author

Thanks
On Jun 20, 2014 11:36 PM, "Narretz" [email protected] wrote:

@TheManFran https://github.com/TheManFran I seems like this issue is
resolved, so I'm going to close it. Feel free to reopen it if there's more
to it.


Reply to this email directly or view it on GitHub
#7716 (comment).

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants