I am completely new to AngularJS. In the code I am supposed to add a feature to I can see $scope.$parent I know about $scope. I also know that when I see a $ it means it is built-in angular. So I searched for it in Angular web site but
I did not have any luck finding anything about $Parent as a built-in service or factory or directive, etc...
Can anybody help me understand what it means. Also how I can get to an answer in their documentation when I run into something new?
The documentation for $parent is sparse, but you can find it referenced here at the very bottom of the page.
$scope.$parent refers to the $scope of the parent element. E.g. if you have an element with a controller nested within another element with it's own controller:
<div ng-controller="parentController">
... something in the parent element
<div ng-controller="childController">
... something in the child element
</div>
</div>
You can access variables attached to the parentController from the childController using $scope.$parent. and use them in the child element.
In angular, your scopes are all chained together. So, you can reference the scope "above" your immediate scope with $parent.
It's useful, for example, if you are working with a directive (or if you have a controller inside of another).
Related
I am trying to understand a working code. It can build a very simple json data by adding name:value pairs one by one with GUI; by a custom directive and its link function, it builds a html template as the right hand of the image below:
What puzzles me is ng-model="$parent.keyName" in the highlighted part, as well as $parent.valueType, ng-model="$parent.valueName" in other part.
1) What does the $parent refer to (in the code or in the example of the above image)?
2) Is there a way to show the value of $parent or $parent.keyName in the console or by adding something (e.g., alert) in the program?
1) $parent refers to the parent scope (of any given scope). All scopes have a parent apart from $rootScope which is the top level scope. They can be created by any angular ng-* directive, including but not limited to ng-controller.
Generally speaking, it's considered bad practice to use $parent because it refers to the immediate parent scope which is subject to change. If the scope hierarchy does change (which it could do by adding a ng-* directive to a html element held in a custom directive template for example) then the hierarchy can be broken and $parent won't refer to the same scope that it once did.
2) Yes you can. In Chrome developer tools, if you Right Click > Inspect Element (as you have in the screen shot), you select the element. Then if you leave that element highlighted and go to the console tab and type:
angular.element($0).scope()
That returns the scope that the selected element resides in. Then if you type:
angular.element($0).scope().$parent()
That returns the parent scope of the scope that the selected element resides in. And for what it's worth you can also do:
angular.element($0).scope().$parent().$parent()
and keep going up the scope hierarchy.
Also check out the AngularJS Batarang chrome extension which allows you to look through the scopes in the Chrome Developer Tools.
What does this $parent refer to?
Parent refers to the scope of your parent controller. The image in your question doesn't give a clear picture so I will add an example for it.
<div ng-controller="EditorController">
<div ng-controller="ChildEditorController">
....
</div>
</div>
Assume you have a property called editorsList (array) in your EditorController (which is the parent controller here), you can do something like
<div ng-controller="EditorController">
<div ng-controller="ChildEditorController">
Editors Count: {{$parent.editorsList.length}}
</div>
</div>
So you can access the scope of your parent with the $parent.
I just started out with Angular and have been reading through a lot of Tutorials.
Now the free one at CodeSchool which was my starting point doesn't mention $scope at all.
From what I've gathered, the controllerAs syntax is relatively new (1.2.0) but it seems to allow you to get away without using $scope directly.
Some articles say "use controllerAs" with an explanation, but most just use $scope. But I couldn't find any explanation why they'd choose it.
Is this now mainly a case of favoring one over the other or are there still reasons to use $scope?
Even many new directive plugins use it instead of allowing you to bind it to a particular controller.
edit: To clarify, I want to know when to use $scope, not the reasons not to use it :)
In the Angular documentation for ngController it explains the advantages to using 'controller as' vs. injecting $scope. Here's what it says:
Using controller as makes it obvious which controller you are accessing in the template when multiple controllers apply to an element.
If you are writing your controllers as classes you have easier access to the properties and methods, which will appear on the scope, from inside the controller code.
Since there is always a . in the bindings, you don't have to worry about prototypal inheritance masking primitives.
For my own part I've found using 'controller as' quite beneficial as it forces me to consider whether code I'm adding to a controller would be more appropriately added into a service or directive.
For example: watches. Watches are something you should avoid in controllers but having easy access to $scope allows you to set them up easily. Using 'controller as' has forced me to think more carefully about whether I really need to do a watch. Usually a watch can be accomplished with a directive. This has led me to create smaller controllers that only set up an initial state and communicate with services, a pattern I've found much more performant and maintainable.
The best answer I can give you is this:
The short:
Whenever you want to expose logic to the template, use Scope.
Whenever you want to persist logic to an element, use ngController.
If you want to expose your controller's values directly in the template (through the scope), use the "controller as syntax".
The long:
An Explanation
Scope or $scope, as you've put it, is where we maintain values (no matter the type: Function, Object, String, etc.) that may be available to the template within that scope. For example, consider the following:
The HTML:
<div ng-controller="MyCtrl">
<div>{{ message }}</div>
</div>
<div ng-controller="MyCtrl as ctrl">
<div>{{ ctrl.message }}</div>
</div>
See those interpolations? Well, guess what? They're both accessing Scope. The "controller as syntax" creates an alias for MyCtrl and publishes it on the local scope. Once the element has been linked, if you look at $scope you will actually find a property ctrl that exposes the controller.
The Javascript
function MyCtrl($scope) {
$scope.message = "controller MyCtrl";
this.message = "controller as syntax";
}
Where ever I use MyCtrl these two messages are available. But to readily access a value on the controller itself we use the "controller as alias" syntax.
They are honestly two different methodologies. The controller as * syntax allows the developer to put the controller onto the scope and more easily access said controller. So, in the end it all ends up on the scope. Otherwise, say through a directive's link function, you have to access the controller the require property. The controller's methods and properties don't necessarily need to be exposed to the template, rather just used in the logic. (In addition, you can access a controller through a jqLite's data() function as well).
Sometimes when propagating a controller to multiple elements we want something that is available by default to every element that uses this controller. This is particularly valuable when creating directives. Take a look at ngModel and see how we have multiple methods common to every element that uses ngModel.
Scope vs. Controller
The major thing to consider is that a child controller can inherit the scope of it's parent. The cool thing is that the child scope will inherit that bit of parental controller properties from the parent.
<!-- ctrl1 -->
<div ng-controller="MyCtrl as ctrl1">
<div>{{ ctrl1.message }}</div>
<!-- ctrl2 -->
<div ng-controller="MyCtrl as ctrl2">
<div>{{ ctrl2.message }}</div>
</div>
</div>
Notice that both are using the same controller but they have different aliases. Now, the controller properties are being passed down to the children through Scope. So the child can access the parent through it's alias. So, through this syntax you can clearly see the separation of the two instances of MyCtrl. They both have a message property on their scopes, but they are easily distinguished without digging through parents, children, siblings, etc.
In Conclusion
If you want to expose values to the template use scope. If you want to bind values to an element that don't necessarily need to be exposed in the template, use the controller. If you need to access values from your controller in your template, use the controller as syntax. Using the controller as * syntax places the controller's values on the scope under the alias created in the syntax. So, in that case, you are using both the controller and the scope together.
As stated in the Angular documentation the benefits are
Using controller as makes it obvious which controller you are
accessing in the template when multiple controllers apply to an
element.
If you are writing your controllers as classes you have easier access to the properties and methods, which will appear on the scope,
from inside the controller code.
Since there is always a . in the bindings, you don't have to worry about prototypal inheritance masking primitives.
I really like it since it makes it easy to differentiate between which controller I am currently accessing.
I read a few blogs and came to a conclusion for usage purpose do not mix $scope and this.
There is a reason for that , "this" and $scope can be different they are not always the same for example-
If I have defined a controller on "this" and I call another controller in it then the $scope will be set to the controller I called but "this" will always be the current context that is the controller in which I called the other controller.
So in this case $scope and "this" will not be same and using them interchangeably here may lead to some unexprcted behaviour.
Please correct me If I am wrong.
I am unable to call a controller function from inside a custom-template with ui-typeahead:
<input typeahead="val for val in autoComplete($viewValue)"
typeahead-template-url="searchAutocompleteTpl.html"
ng-model="query"/>
<script type="text/ng-template" id="searchAutocompleteTpl.html">
<span ng-repeat="eqp in match.model.equipment"/>
<a href="" ng-click="showItem(eqp.model)">
found in: {{eqp.model}}
</a>
</script>
The problem is that the controller's scope seems to be absent in the template:
showItem(eqp.model)
is never called. I have also tried with:
$parent.showItem(eqp.model)
to no avail.
How can I call a function/value on the controller's scope then?
I ran into the same problem and had a look at the typeahead code on github to see if that might offer any clues. It appears that there are several directives involved in the creation of the suggestions list and each gets its own child scope.
In other words, your $parent.showItem(eqp.model) was a good attempt, but you didn't go up enough levels. What worked for me was: $parent.$parent.$parent.showItem(eqp.model)
I also have same problem. I'm not sure but its working.
You can use double $parent instead of single.
e.g. $parent.$parent.showItem(eqp.model)
The solution of your problem is to initiate an object in your template controller scope like this:
$scope.typeaheadObject = {
query : '',
}
now in your form you will need to change your ng-model with:
ng-model="typeaheadObject.query'
This will create the object typeaheadObject in all your controller if you don't re-initiate it in one of your controller. So when you will want to access to the content of the object in one of this controller you will just have to do for example:
console.log($scope.typeaheadObject.query)
This is a classical issue in angularJs. You only can access and modify a parent scope if the variable is stock in an object
Finally you have to use a '.' in your ng-model. This will permit your ui-bootstrap module and your own module to share their scope with the object.
I just did an example on plunker to be sure you understand well the issue.
http://plnkr.co/edit/4YWNMagm571Gk2DrCERX?p=preview
Have a good day :)
It worked for me after adding 4 parents.
$parent.$parent.$parent.$parent.
I'm pulling my hair about a particular issue with my AngularJS application.
Basically, I have a controller, "PageCtrl", which pulls in a list of data via a service. The data is saved inside the PageCtrl. All works fine - so far so good.
Now my issue: for each object of the data inside the PageCtrl, I use ng-repeat to display each data just fetched.
In each of the ng-repeats, I use ng-include to get the correct template, depending of which data is in each object (basically the data is a list of elements that is to be displayed on the page. Each element has it's own controller.
As ng-include creates a newscope, all the created child scopes/controllers have access to the data, as it is located in the $parent controller - PageCtrl.
All works fine, except that each created controller in ng-repeat/ng-include needs to know which object in list of data in the parent, it needs to use to display.
Basically, in my ng-repeat, I would like to use the $index and pass it to the controller included in the ng-include. But I cannot do it! If I use ng-init, that code inside ng-init will be executed on the parent scope, ie. my original PageCtrl.
How can I, without the use of directives, pass information to the controller so that it knows which of the data-objects in its parent it should use?
Here is the code that loops over the data in MainCtrl:
<div ng-repeat="element in elements" >
<ng-include src=" GetTemplateFromElement(element.type) " ng-init=" SetElementNo($index); "></ng-include>
</div>
In the snippet, I call GetTemplateFromElement on the MainCtrl which returns the view to include. In the included view I refer which controller should do the work. I try to use $index to tell the included controller which index in the data it should use. But ofcourse the code is executed in MainCtrl scope. Example of a view:
<div ng-controller="ElementDocumentCtrl">
<div ng-bind-html-unsafe="element.document_content"></div>
</div>
In the snippet, "element.document_content" is on the scope of ElementDocumentCtrl, which pulls the data from its parent, PageCtrl.
How can I tell the directives included which index in the data-list in PageCtrl (it's parent controller) it should pick up?
Please don't tell me I need to make them all directives :)
Thanks, guys.
Maybe Im not understanding your question completely, but from the docs, $index, $first, $middle and $last are all exposed on the local scope of the ng-repeat children.
Ive put in a plunker to demonstrate this. The ChildCtrl accesses the $index from the parent to get the index of which element in the parent it is accessing.
Can anyone explain the difference between $scope and $rootScope?
I think
$scope:
We can get ng-model properties in particular controller from the particular page by using this.
$rootScope
We can get all ng-model properties in any controller from any page by using this.
Is this correct? Or anything else?
"$rootScope” is a parent object of all “$scope” angular objects created in a web page.
$scope is created with ng-controller while $rootscope is created with ng-app.
The main difference is the availability of the property assigned with the object. A property assigned with $scope cannot be used outside the controller in which it is defined whereas a property assigned with $rootScope can be used anywhere.
Example: If in the example below you replace $rootScope with $scope the department property will not be populated from the first controller in the second one
angular.module('example', [])
.controller('GreetController', ['$scope', '$rootScope',
function($scope, $rootScope) {
$scope.name = 'World';
$rootScope.department = 'Angular';
}
])
.controller('ListController', ['$scope',
function($scope) {
$scope.names = ['Igor', 'Misko', 'Vojta'];
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="example">
<div class="show-scope-demo">
<div ng-controller="GreetController">
Hello {{name}}!
</div>
<div ng-controller="ListController">
<ol>
<li ng-repeat="name in names">{{name}} from {{department}}</li>
</ol>
</div>
</div>
</body>
According to Angular's Developer's Guide to Scopes:
Each Angular application has exactly one root scope, but may have several child scopes. The application can have multiple scopes, because some directives create new child scopes (refer to directive documentation to see which directives create new scopes). When new scopes are created, they are added as children of their parent scope. This creates a tree structure which parallels the DOM where they're attached.
Both controllers and directives have reference to the scope, but not to each other. This arrangement isolates the controller from the directive as well as from DOM. This is an important point since it makes the controllers view agnostic, which greatly improves the testing story of the applications.
$rootScope is available globally, no matter what controller you are in, whereas $scope is only available to the current controller and it's children.
In other way we can look at this; $rootScope is global while $scope is local. When Controller is assigned to a page, so a $scope variable can be use here because it binds to this controller. But when we want to share its value across to other controllers or services, then $rootScope is being used (**there are alternative ways, we can share values across but in this case we want to use $rootScope).
Your second question about how you define those two words are correct.
Lastly a bit off track, please use $rootScope with care. Similar to the way you use global variables, can be a pain to debug and you may accidentally change the global variable somewhere inside a timer or something which makes your reading incorrect.
Every application has atleast one single rootScope and its lifecycle is the same as the app and every controller can have it's own scope, that is not shared with others.
Have a look at this article :
https://github.com/angular/angular.js/wiki/Understanding-Scopes
I recommend you read the official in-depth Angular documentation for scopes. Start at the section 'Scope Hierarchies':
https://docs.angularjs.org/guide/scope
Essentially, $rootScope and $scope both identify specific parts of the DOM within which
Angular operations are carried out
variables declared as part of either the $rootScope or $scope are available
Anything that belongs to the $rootScope is available globally across your Angular app, whereas anything that belongs to a $scope is available within the part of the DOM to which that scope applies.
The $rootScope is applied to the DOM element that is the root element for the Angular app (hence the name $rootScope). When you add the ng-app directive to an element of the DOM, this becomes the root element of the DOM within which $rootScope is available. In other words, properties etc of $rootScope will be available throughout your entire Angular application.
An Angular $scope (and all of it's variables and operations) is available to a particular subset of the DOM within your application. Specifically, the $scope for any particular controller is available to the part of the DOM to which that particular controller has been applied (using the ng-controller directive). Note though that certain directives e.g. ng-repeat, when applied within a part of the DOM where the controller has been applied, can create child scopes of the main scope - within the same controller - a controller doesn't necessarily contain only one scope.
If you look at the generated HTML when you run your Angular app, you can easily see which DOM elements 'contain' a scope, as Angular adds the class ng-scope on any element to which a scope has been applied (including the root element of the app, which has the $rootScope).
By the way, the '$' sign at the start of $scope and $rootScope is simply an identifier in Angular for stuff that's reserved by Angular.
Note that using $rootScope for sharing variables etc. between modules and controllers isn't generally considered best practice. JavaScript developers talk about avoiding 'pollution' of the global scope by sharing variables there, since there may be clashes later on if a variable of the same name is used somewhere else, without the developer realising it's already declared on the $rootScope. The importance of this increases with the size of the application and the team that's developing it. Ideally the $rootScope will only contain constants or static variables, that are intended to be consistent at all times across the app. A better way of sharing stuff across modules may be to use services and factories, which is a another topic!
Both are Java script objects and the difference is illustrated by diagram as below.
NTB:
First angular application try to find the property of any model or function in $scope , if it doesn't
found the property in $scope , then it search in parent scope in upper hierarchy. If the property is
still not found in upper hierarchy then angular tries to resolve in $rootscope.
New styles, like John Papa's AngularJS Styleguide, are suggesting that we shouldn't be using $scope to save current page's properties at all. Instead we should use the controllerAs with vm approach where the view binds to the controller object itself. Then use a capture variable for this when using the controllerAs syntax. Choose a consistent variable name such as vm, which stands for ViewModel.
You will still need the $scope for its watching capabilities though.