-
Notifications
You must be signed in to change notification settings - Fork 27.6k
New properties are not set on an isolate scope? #5112
Comments
You can "pass callbacks" to directives without isolate scope. ngEventDirs (eg ng-click) provides a simple example of this: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngEventDirs.js#L45 --- by using $parse to build the expression which gets evaluated. So, your directives can do the same thing, if it makes sense to. There's a time and place to use an isolate scope. To my knowledge though, a directive with an isolate scope's controller will actually get the isolate scope, and not the child scope. If it doesn't, you can get the isolate scope with $element.isolateScope() (if you inject $element), so it is technically doable I guess it is doable without element.isolateScope() hacks, that's good Unless I'm misunderstanding your issue... But what I think you're saying is that you're having trouble assigning a property to the isolate scope from a directive's (with an isolate scope's) controller |
@caitp Thanks for the reply, I'm simply trying to set a new property on the scope, in the directive's controller. If I set: $scope.foo = "bar" from within the directive's controller, then, in the template of the directive, if I try to print {{foo}}, it doesn't produce any output. However if I set $scope.$parent.foo = "bar" in the same place, then the {{foo}} line works. If I remove the isolate scope, and then set $scope.foo = "bar", that works as well. But putting the isolate scope back in makes it ignore any additional properties that I set. I don't see the reason why, because it makes things very inconvinient. |
If "foo" is defined in the isolate scope, I think you're going to have an issue with that (because it will be overwritten every digest cycle as the expression it's bound to is evaluated again). I might actually be wrong about that, but definitely you can reference properties which aren't declared in the isolate scope object from your directives controller (example) Yeah, so the reason you can't change properties defined in the isolate scope object (the You could work around it by changing the attributes themselves, or deleting the observers/watchers from scope. |
@caitp Please see this fork of your plunkr: http://plnkr.co/edit/lTCRrnWtkESiNwpPP3Ph?p=preview Here, I'm setting a new property on $scope called foo, but its not being displayed when I try to output it via {{foo}} If you delete the isolate scope from the directive and refresh it, then you will see the value of foo being output. Is this expected behavior? |
Sorry, correct url: http://plnkr.co/edit/lTCRrnWtkESiNwpPP3Ph?p=preview |
Yeah, it doesn't work that way --- the isolate scope applies only to the directive (and its template, if it has one), not to child nodes |
What are you referring to as the child node here? |
<div iso-box="true">foo: {{foo}}</div> in 1.2, the text node will be watched using the parent scope, not the directive's isolate scope |
Why is that? Clearly, it should fall under the directive's scope since its included in the directive's parent element. Using the parent's scope is very unintuitive. Also, it breaks code written with previous versions. |
Intuitively, if you include a directive as an attribute, e.g:
then you would expect all the child elements of that div to be included in the |
Imo, it was a good idea to make isolate scopes truly isolate, but I didn't really understand the need to exclude child nodes that are not defined in the template from getting the isolate scope. I mean how could the devs know that "In theory, nobody should rely on this behavior, as it is very rare - in most cases the isolate directive has a template"? |
@Narretz I agree with you. The very point of allowing directives as attributes on existing elements (e.g divs) means that you should be able to access the directive's scope within that element. For example, I have an 'ajaxForm' directive, which I set on any normal |
@Narretz: There is no reason why someone couldn't simply use a child scope, if they want to use it like that. I know isolate scopes look "convenient" (and they are, in a sense), but it's not necessary to use those conveniences, you have other options (as I've pointed out in examples). So you aren't stuck using an isolate scope, and you should really only use it when it's appropriate. Have you thought about using an isolate scope + transclusion to keep your child nodes intact? (they wouldn't be able to see the isolate scope, but they wouldn't have to be thrown away) |
@caitp I am only using the isolated scope where appropriate in my ajaxForm directive example given above. Also, I've updated my plunkr to use transclusion here: http://plnkr.co/edit/lTCRrnWtkESiNwpPP3Ph?p=preview But, its still unable to access scope.foo being set from the directive. I don't see why the scope of the directive should not be accessible to the child elements of the parent element which has the directive as an attribute. If you set ng-controller as an attribute on any element, all the children of that element do get the controller's scope. Its only consistent and intuitive to keep the same behavior for directives. |
no, transclusion will keep your child nodes, but they will not have access to the isolate scope --- they reference the parent scope. (using ng-transclude in your template will let you reference the isolate scope without discarding child nodes that you want to keep) you need to either create a child scope rather than an isolate scope, or put every reference to your isolate properties in a template. Anyways, the issue tracker isn't really the place for these kinds of support questsions, you should ask on the mailing list or on #angularjs on irc.freenode.net to get answers to support questions. Everything here is covered in the BREAKING CHANGES in the changelog, so please consult with that as well |
But that's bad design, and should be changed for the reasons I gave above. |
Also I can't use a single template when each form that I want to use my directive on, has different fields. |
you can dynamically compile templates, you can simply use a child scope rather than an isolate scope --- you are not limited here, there are lots of things you can do. |
But I shouldn't have to do these complicated workarounds for what should work intuitively, i.e if you set a directive as an attribute on an element, the children of that element should fall under the directive's scope, just as if you do ng-controller on an element, its children all get the controller's scope. |
http://plnkr.co/edit/zW1RCU00fbc6wIDLNotX this works just fine (despite creating an extra child scope), it's not all hopeless Anyways, an isolate scope must be isolate --- it should not leak into other directives, or child nodes, that's not what it is meant to do. You can tell by the name --- "isolate" is clearly meant to not leak around. It did prior to 1.2, but this was not intentional afaik. Again, this isn't really an appropriate place for support questions --- if you aren't happy with it, it would be good to propose improvements on the google group or on the IRC channel.
ng-controller creates a child scope, not an isolate scope. |
Isolate scopes are special and in general it is expected that their children are going to be transcluded into a template. As such it is slightly fiddly to get what you want working - but only very slightly! You just use the fact that template can be a function. Here is a fiddle: http://jsfiddle.net/NTuS6/ |
Interesting. I guess stuff like "in general it is expected that their children are going to be transcluded into a template" should go in a doc section called "directive examples and best practices". I have the feeling that what was intended by the devs for directives is often not how people use the mechanics. |
I'm a little confused about the "children are going to be transcluded into a template" bit... I've updated the fiddle from @petebacondarwin to use a template + transclusion and still the children don't have access to the isolate scope. I'm surely missing something... what it is? |
@wtfribley what is going here is that you are transcluding the contents of the parent element to the new template. Here we are writing to the transcluded template, but only because we are overriding the original scope that the transcludeFn is bounded too. |
This seems to have been resolved, so I'm closing it. It'd be nice to clarify the points brought up this issue in the AngularJS docs. Any takers? :) |
was quite confused about this one, too. thanks for all of the clarifications here, i'm using the 'template function' approach by @petebacondarwin and am happy with it. |
If I have a directive with an isolate scope, and I wanted to set a new property on that isolate scope within the controller of that directive, those properties seem to not get set. Why is that?
I use isolate scope only because there's no other way to pass callbacks / functions to a directive. But now I'm finding that I can't set any properties on the isolate scope, other than what I've defined.
Please advise..
The text was updated successfully, but these errors were encountered: