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.
Related
I would like to know what is the main difference between "Controller as" or "$scope" syntax in angularjs.
Do they have any performance impact,if yes which syntax is preferable.
"Controller as" syntax surely improve the readability of the code,as Knockout.js and other JavaScript framework follows the same syntax.
$scope will provide scope inheritance which sometimes give us weird behavior like
<div ng-controller="firstController">
ParentController: <input type="text" ng-model="parent"/>
<div ng-controller="secondController">
ChildController: <input type="text" ng-model="parent" />
</div>
</div>
app.controller('ParentController', function ($scope) {
$scope.parent = "parentScope";
}).controller('ChildController', function ($scope) { /*empty*/ });
a) Initially child will get the parent property and it displays 'parentScope' when we update parent child will also get updated. But if we have changed the child property now updating the parent doesn't modify child as it has got its own scope property.
b) If i am using controller as syntax changing child also updates the parent.
I've written a few answers to this question in the past, and they all essentially boil down to the same thing. In Angular, you are using $scope, even when you aren't expressly referencing it.
The ControllerAs syntax allows Angular to help you to write more efficient, fault tolerant controllers. Behind the scenes, when you use ng-controller="theController as ctrl", Angular creates theController as a property on $scope and assigns it as ctrl. You now have an object property you are referencing from scope, and are automatically protected from prototype inheritance issues.
From a performance perspective, since you are still using $scope, there should be little to no performance difference. However, since your controller is now not assigning variables directly to $scope on it's own, it does not need to have $scope injected. Also, the controller can much more easily be tested in isolation, since it is now just a plain JavaScript function.
From a forward thinking perspective, it's well known by now that Angular 2.0 will not have $scope, but instead will use features of ECMAScript 6. In any previews released by the Angular team showing migrations, they first begin by refactoring the controller to eliminate $scope. If your code is designed without the use of $scope based controllers, your first step in a migration is already complete.
From the designer's perspective, the ControllerAs syntax makes it much clearer where objects are being manipulated. Having customerCtrl.Address and storeCtrl.Address makes it much easier to identify that you have an address assigned by multiple different controllers for different purposes than if both used $scope.Address. Having two different HTML elements on a page which both are bound to {{Address}} and knowing which one is which only by the controller the element is contained in is a major pain to troubleshoot.
Ultimately, unless you are trying to spin up a 10 minute demo, you really should be using ControllerAs for any serious Angular work.
I would definitely recommend Controller As syntax.
It's cleaner, more efficient, you can organise your code much more and it's the new way of doing AngularJS.
Unless you're working with a team used to the $scope syntax, definitely use Controller As.
This entire weekend, I was in much distress, not understanding why a parent controller's function was not being recognized by a child controller.
I soon realized that having my controller as vm was the cause:
<div data-ng-controller="ParentCtrl as vm">
<div data-ng-controller="Child1 as vm"></div>
<div data-ng-controller="Child2 as vm"></div>
</div>
Sure, it all seems obvious now that neither child1 nor 2 will see functions in ParentCtrl, and if instead I had used the prior pattern of working without vm, and instead had $scope, all would be well.
So my question is "What does it benefit anyone for using the "vm" method, and if it is superior to not using it, how can one call function calls in the ParentCtrl short of emit?
Thank You
One advantage of using the controller as syntax is that it allows you to define your controllers as a simple javascript constructor function with properties and functions exposed directly from the instantiated object rather than the $scope.
For example:
function MyController() {
var ctl = this;
ctl.message = 'You have not clicked anything yet.';
ctl.onClick = function() {
ctl.message = 'You clicked something.';
};
return ctl;
}
...
myModule.controller('MyController', MyController);
...
<div ng-controller="MyController as vm">
<span>{{vm.message}}</span>
<button ng-click="vm.onClick()">Click Me</button>
</div>
Notice that we are able to use a controller that is plain old javascript without even being tied to angular. For scenarios where you need additional dependencies such as $scope or other services, you can still easily pass them in to your constructor, but this pattern encourages less clutter directly on your $scope and also solves the problem of variable hiding when variables are set directly on the scope.
Ultimately it really comes down to a matter of preference, but for me I really like not having to define everything directly on the scope and to treat my controllers as any old javascript object as much as possible.
Here's an excellent article on the usage of controller as:
http://www.johnpapa.net/angularjss-controller-as-and-the-vm-variable/
I used to use controller as vm syntax, but lately I've been moving away from it. I'm finding that when I build complex pages with nested directives using scope isolation, the traditional $scope approach is far easier to work with.
Your question is one I wondered about for a while. The only real value I can see is that when you use nested controllers in a page, you can get semantic reference to each of the scopes so that your markup becomes a little easier to read. So, for instance:
<div ng-controller="CustomersCtrl as customers">
<div ng-controller="OrdersCtrl as orders">
<p>Showing{{customers.model.length}} customers with a total of {{orders.model.length}} orders</p>
</div>
</div>
Other than this, I don't really see the value and if you prefer nesting with directives as I do, the value is quickly nullified imho.
What you are experiencing with this example is not specifically due to the use of the controller as syntax; instead, it is due to your nested objects hiding the parent due to naming.
The controller as option is highly useful when working extensively with other languages that compile to JavaScript such as CoffeeScript or TypeScript. It also allows you to create much more lightweight controllers which can be interchanged with non-angular components, due to not needing the $scope injection. It is simply an alternate syntax, but you can still use $scope if you wish.
The real question here is why people who have written examples of the controller as syntax have decided to use the "as vm". Technically, the syntax is designed to provide an MVVM style coding experience, and so using "as vm" may make sense, but this exposes the issue you are seeing. Your parent controller is an object named vm, and your child object is also named vm, so the child object is hiding the parent object from view. If, instead, you name your objects differently, your child object will have no issue accessing the parent object, and it will actually be very clear in code which object the property you are working with is coming from.
I think one of the main advantages is that it automatically makes sure you'll end up with a . in your bindings. Because the rule of thumb in Angular is that if you don't have a . in your bindings you might shoot yourself in the foot.
Consider you have this:
<input ng-model="foo" />
This might not work as intended. On the other hand, if you use the SomeController as vm syntax you would automatically end up with this:
<input ng-model="vm.foo" />
This will save you from the potential trouble with the data binding not working as expected.
The reasons behind that lay in the way prototypal inheritance works in JavaScript and it's been described in very much detail here: What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
As I understand, the main reason to use "controller as vm" syntax is that controllers in angularjs actually serve as models(encapsulate data and provide behaviours), or view models(expose data to html).
In most cases it worked well, but one main fallback I've encountered is that it's difficult to access data in parent controller from child controller, and possible solution(Get parent controller in child controller which all use 'controller as vm' notation) is not elegant.
I am looking at some samples of how controllers work in angular and I see two ways of declaring them, one with just controller name and one with "as somename". Examples that use ng-controller = "myController" take a $scope as dependency when defining controller.
Then model is then set on the $scope, something like this
$scope.mymodel = somevalue;
Example that uses "as" syntax such as ng-controller = "MyControler as vm" never uses $scope when setting up the model but ratther assigns it to "this" and binds using {{vm.something}}.
in controller:
var vm =this;
vm.something = somevalue;
How is that working in second example? Is that new way in latest version?
Using the "as" syntax exposes your entire controller to your view. In my opinion, that is a bad practice. Although I'm not sure which one is better performance wise, but using 'this' in javascript already has plenty of issues of its own, and I don't recommend adding another meaning to 'this'. So I would stick to $scope (since that is what they're using in the docs as well).
See this topic if you want to know more context about how the 'as' syntax work: 'this' vs $scope in AngularJS controllers
Use case
For use in a form, I created a directive that tracks changes in an array. It allows changes to be reverted and deletions and additions to be stored separately. It allows for an array (one to many mapping in the database) to be updated incrementally (rather than requiring the server to either diff, or rewrite the entire list).
Problem?
My question is about the way I expose the functionality to the controller's scope. I currently use an two-way databound attribute on the directive's scope. This works, and it seems reliable (of course you can easily break it by reassigning the scope's value, but intentionally you can break anything).
Code
You can see this plunk to see this in action. It allows methods on the directive's controller to be called from the view and the view's controller. (I am using the directive controller intentionally because that's what I do in my actual code for the directive to directive communication, but this could also just be placed in the linking function.)
Question
Is this way of doing it bad design? Am I completely throwing AngularJS out of the window now and hacking in my own code. Are there any better ways to expose functions from a directive (keep in mind that there'll be multiple of these in a single form).
It's very easy to pass in my-attribute="someFunction()" to have the directive be a consumer of the view controller. I can't find a better way to do the opposite and have the view controller consume from the directive.
Alternative?
I've been thinking about using a service here, in which the service will provide an object that is instanciated in the view, passed to the directive, and have the directive blurp out it's results to that object. Then in turn have the view controller consume the information from that service's object. Would this be a better approach?
There's nothing wrong with your approach. In fact built-in angular directives such as ng-form use this approach to store the controller in the scope (see the name property of ng-form) http://docs.angularjs.org/api/ng.directive:ngForm
For more re-usability though I would put the api methods on the controller and then put the controller itself in the api:
this.getChanges = function () {};
this.resetChanges = function(){};
$scope.api = this;
In directives, the main purpose of the controller is to serve as an api for other directives (if you didn't need an api for other directives you could just do everything in the link function). Doing it this way ensures the api is available both on the scope as well as to any directive that 'requires' the oneToMany directive.
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.