I would like to know if there is a way to access the $scopes variables using the $rootScope such that if a function is defined in scope I can invoke it using $rootscope to or if there is a variable defined using $scope.var1 I could access it using $rootScope to
Every scope have a two property references to its child scopes, namely: $$childHead and $$childTail. Additionally every scope object has $$nextSibling and $$prevSibling properties pointing to same-level scope sibling instances. Having this properties you can travers all child scopes horizontally or vertically. Depending why you need to do it on each step you would check for necessary scope property or method.
That being said, I can't see real business-logic application for such child scope traversal, except for logging/debugging purposes, for example to build scope hierarchy tree, etc.
Related
As far as I know that basically scope is an instance of a controller.
Every time I declare a controller scope will be available for that controller.
But then why directive has scope in link function ?
I didn't declare any controller for the directive.
Then why link function has scope ? Any Idea ?
From the doc:
scope:
The scope to be used by the directive for registering watches.
You may also be interested to see the differences between $scope and scope.
All directives have a scope associated with them. They use this scope for accessing data/methods inside the template and link function. By default, unless explicitly set, directives don’t create their own scope. Therefore, directives use their parent scope ( usually a controller ) as their own.
However, AngularJS allows us to change the default scope of directives by passing a configuration object known as directive definition object. A directive definition object –– let’s call it as DDO –– is a simple JavaScript object used for configuring the directive’s behaviour,template..etc. Check out AngularJS docs about DDO.
So, we can use scope inside linking function to work with parent scope, child scope or isolated scope.
You may visit this for detailed information about scope inside directive.
You can share the data between controller and linking function.
Sometimes we would like to access that same data in both controller and link functions in Angular directive. Usually we add this data to the scope object. This has certain problems, for example exposing it to any child scope. Add the shared properties to the controller instance itself and access in the link function.
You may also be interested in what is need of link function?
A directive is Angular's way of defining 'components': you specify how its markup looks and how it behaves before, during and after being rendered. The link functions allow you to hook up events to the DOM element before or after it gets 'linked' (see also: pre-link and post-link methods). When these events are fired you might want to change some of the variables within the scope, and that's why you have access to it within the link functions.
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!
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
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.
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.