angularJS seems to create new scopes, in that there are parent scope, child scope, and sibling scope.
What determines when a new scope is created? For example, if I use ng-inspector to view the scopes present, there is the $rootScope, and also other scopes, but it is not obvious to me what the other scopes correspond to, nor is it clear to me when these other scopes are created/destroyed. I believe they are created/destroyed because the $id changes. Changes occur if I navigate around and press forwards/back.
Angular creates new scope for every instantiated controller on that part of DOM.
Angular also creates scope for every directive (except scope:false, that means for directives with isolated scope, and scope:true). A scope is also created for built in directives such as ng-repeat where it creates scope for every repeated item.
Also when you use ng-if directive it can remove and add parts of the DOM and when it adds it all the controllers and directives will add their scopes again.
Angular's scope tree pretty much will mirror the dom tree. Directives can create new scope. Not just your directives, but also built in Angular directives like ng-if. It's a bit of an in depth topic...
Here is a blog post that explains things more in depth.
Hope that helps!
Related
While implementing directive I came across isolate scope , I am having Confusion why we have to Use isolate scope instead of scope.
When using an isolated scope, the directive's scope does not prototypically inherit from its parent. The directive has no access to the parent scope. This gives you the highest encapsulation. You should use an isolated scope, whenever you're designing reusable components.
Directives have access to the parent scope by default. For example, the following directive relies on the parent scope to write out a user object’s name:
angular.module('myDirective').directive('sharedScope', function () {
return {
template: 'Name: {{user.name}}'
};
});
The problem with this code is that you need to have an information about the parent scope, thus if the parent scope changes? The directive will become not usable anymore. That's when isolated scope comes in handy. Therefore isolated scope is used whenever directive is designed to be reusable. These are some good blog post which explain in depth the topic
AngularJS Directives, Using Isolated Scope with Attributes
Angularjs Sticky Notes
Creating Custom AngularJS
directives
A small question about $$nextSibling. I've seen a lot of articles similar to this one that say that the relationship between a directive with isolate scope and transclude scope is through $$nextSibling. This seems to be correct if there is only one instance of the directive. However, I have a collection directive that contains items which are also directives e.g.
<items><item id="1"/><item id="2"/></items>
and this creates 4 sibling scopes but in this order: item 1 isolate, item 2 isolate, item 1 transclude, item 2 transclude. In this case you need $$nextSibling.$$nextSibling which is very unsatisfactory.
Is there a cleaner way to reference between the isolate and transclude scopes?
I am trying to make self contained controls that 'emit' messages to be received by the first parent directive that is listening for that message. I'm finding that the messages are received by the transclude scope of the parent and not the isolate scope (which I understand and is fine). The problem comes in because my parent controls 'model' is on the isolate scope so taking action after receiving the message means interaction between the transclude scope and the isolate scope - normally via $$nextSibling. However, as described above this is not predictable once you start to have collections.
Thanks.
The answer to this is version dependent. I was running on v1.2.0 of angular. In this version sibling scopes are not correctly ordered so that $$nextSibling is NOT reliable.
After installing v1.2.7 this is now fixed and the sibling scopes are listed in the correct order with the transclude scope always following the isolate scope.
From an initial read through of the version change log it is not immediately obvious which fix resolved this issue so I'm not sure what the earliest version of Angular that resolves this issue is.
Is it correct that angular does not create an isolate scope for a element that has two directives on it where the highest priority directive does not have an isolate scope and the lower priority directive does?
I have the following plunker that has 2 directives and a controller:
http://plnkr.co/edit/zEnMH6h0ILURHSgx0DLX?p=preview
If you open up the console, you can see the logs of the scopes of the directives and controller. The noIsoScope directive does not have a isolate scope and has a priority of 1. The isoScope scope directive has an isolate scope but a priority of 0. When I use each directive independently, everything works as excepted. When I use both of them together, the isoScope directive shows that is it using the controller scope (since based on the logs, it has the same $id) instead of its own.
Do I have to make sure that whenever I am using multiple directive on an element, if one of them has an isolate scope, that it has to have the highest priority?
Short answer yes.
It doesn't make sense to have 2 directives require both an isolate scope AND a parent scope. The idea would be to think about how directive can work with each other. How would the parent scope directive work correctly if the scope it has is the isolate scope?
I guess the angular team decided to not give a warning in this situation(could be a bug).
if the lower priority requires a isolate scope that means it has a strict requirement of data from parent scopes
if the higher priority doesn't require a scope that means it will inherit the parent scope and potentially use that data in the template.
This is a catch 22 situation:
It doesn't make sense that the non isolate directive use a isolate scope since it might depend on the fact that it's not isolate.
At the same time the isolate directive most likely depends on the fact that it's isolate.
From Igor Minar, he's talking about multiple isolate scopes but it's the same issue basically:
My suggestion is to use isolate scopes when you are creating reusable components that are backed by a template. If you want to compose multiple directives together, you should design them in a way that make one directive the main one (with the template) and the other directives are just helper directives (sort of like traits or mixins in some programming languages).
I have two different custom directives, both having an isolated scope. Is there a way to use both directives on the same element without getting:
Error: Multiple directives [...] asking for isolated scope on ...
I thought that they would share a common scope by doing so but it appears it won't (as I get this error)...
Thanks
Tom
OK, I've workarounded that issue by using the same controller for my both directives, allowing them to share the scope different from the parent scope...
I'm still interested in any suggestion on that subject.
There's a summary of how directive scopes can be combined in the reference to the $compile method.
The main points are that isolate scopes are never shared, and that an element can have at most one scope attached to it. If your directives use a child scope instead, then it will be shared between both directives.
no scope + no scope => Two directives which don't require their own scope will use their parent's scope
child scope + no scope => Both directives will share one single child scope
child scope + child scope => Both directives will share one single child scope
isolated scope + no scope => The isolated directive will use it's own created isolated scope. The other directive will use its parent's
scope
isolated scope + child scope => Won't work! Only one scope can be related to one element. Therefore these directives cannot be applied
to the same element.
isolated scope + isolated scope => Won't work! Only one scope can be related to one element. Therefore these directives cannot be applied
to the same element.
Well, I think Angular gives you the choice between working with a parent scope and communicating between directives.
You can achieve the latter one by adding an interface in the "master" directive by adding a controller function which the "slave" directive consumes. The slave explicates the dependency via require: '^masterDirective' and can use its interface in the link function.
See the official explanation with a nice example: https://docs.angularjs.org/guide/directive#creating-directives-that-communicate
I have a shared function which returns of the scope of the topmost element (document) in my AngularJS application.
function topScope() {
return angular.element(document).scope();
}
This always works and I am always guaranteed to have access to any subscopes located within the application (whether it be inside controllers or directives).
Here's an example of what I would use it for:
topScope().$emit('pageReady');
Now I've noticed that $rootScope also works the same way.
$rootScope.$emit('pageReady');
Which also works and achieves the same affect. But since $rootScope is designed to be the "$scope off the shelf" scope (any scope created will inherit it's methods and properties) then does this still mean that it is in fact the topmost scope of the page? Thus being the parent of the scope object attached to the document node?
$rootScope is a parent scope of all scopes in a given AngularJS application. Since it is possible to bootstrap multiple AngularJS applications on one page (only manually, this can't be done using ng-app) it is also possible to have multiple $rootScope instances in one HTML documents.
Each $rootScope is "attached" to either the element where ngApp was declared or the element passed into angular.bootstrap as described here.
In short, the $rootScope is a root of all scopes for one AngularJS application but there is no "super-root" scope that would serve as a parent scope of all other scopes for a given HTML document.
In your case using the $rootScope might be OK if you've got only one AngularJS application in the whole HTML document.