What does 'var vm = this;' mean in angular controllers? - angularjs

I was browsing some stuff on github and I saw inside controller.js, someone had put the following:
function ImageController ($scope, $timeout) {
var vm = this;
}
What is this used for?

The vm in this case means viewmodel.
It is a shortcut, so instead of writing this.someMethod() you can use vm.someMethod().
Very common when you use Controller As syntax, so you don´t use the $scope by "accident".
Also, the this keyword can be messy to use, since it may reference different things depending on where it is used.

Why?: Helps avoid the temptation of using $scope methods inside a
controller when it may otherwise be better to avoid them or move the
method to a factory, and reference them from the controller.
you can check full John Papa Angular Style to learn deeper...

Related

Opinions agains using $rootScope excesivelly

I would like to persuade my co-worker that it is a better approach to use component directives than to use $rootScope everywhere. I need arguments against his ones because he is very stubborn and a very good speaker (which I am not). He thinks that $rootScope prevents spaghetti code. This week I have refactored the project and there are no more spaghetti but I don't want him to rework everything to $rootScope.
Please tell me about problems and issues that can arise when using $rootScope. Thank you.
EDIT
Are there any security issues with $rootScope?
EDIT 2
My friend came with this construct and wants to put it in every component:
function Controller(service, $rootScope, $scope) {
var vm = this;
$scope.a = $rootScope.a;
$scope.b = $rootScope.b;
$scope.c = $rootScope.c;
$rootScope.$watch('mapLoaded', function () {
$scope.a = $rootScope.a;
$scope.b = $rootScope.b;
$scope.c = $rootScope.c;
}, true);
Would the issue of destroying scopes and removing wathces that #charlietfl described in comments appear? I am definitelly not gonna let him code like this but I need the arguments against it. Thanks again.
$rootScope exists, but it can be used for evil
Scopes in Angular form a hierarchy, prototypally inheriting from a root scope at the top of the tree. Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
Occasionally there are pieces of data that you want to make global to the whole app. For these, you can inject $rootScope and set values on it like any other scope. Since the scopes inherit from the root scope, these values will be available to the expressions attached to directives like ng-show just like values on your local $scope.
Of course, global state sucks and you should use $rootScope sparingly, like you would (hopefully) use with global variables in any language. In particular, don't use it for code, only data. If you're tempted to put a function on $rootScope, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
-- AngularJS FAQ
I will response myself to Edit 2 citing this:
Using $watch means whenever you read this code in the future you’ll
have to consider whether it’s being triggered by something else, too.

using $scope with controller as syntax

UPDATE
here's the article where I saw the examples below: https://github.com/johnpapa/angular-styleguide
after re-reading the example I realized that a specific and unique scenario was being explained, thus this question may not be fully valid. I will not delete it, however, so that if anyone has any further knowledge, they can contribute and help the community.
I've been reading about angular best practices and I'm convinced after reading a few articles that the best approach is to use the controller as syntax:
angular.module('example', [])
.controller('somectr', somectr);
somectr.$inject =['$http'];
function somectr($http) {
var vm = this;
this.x;
}
however I saw an article that shows this syntax, but it also injects a scope:
somectr.$inject = ['$scope', '$http'];
function somectr($scope, $http) {
var vm = this;
this.x;
this.y;
$scope.someFunc = function() {}
}
I thought that using the controller as syntax means no need to use a scope object. What user case would require the controller as syntax but still make use of a scope object?
An example of injecting $scope even if you are using controllerAs is when you want to pub/sub events.
If you want to Publish some events, you would use:
$scope.$broadcast('eventName', value)
$scope.$emit('eventName', value)
For Subscribing:
$scope.$on('eventName', function)
Take a further look at: https://docs.angularjs.org/api/ng/type/$rootScope.Scope
Another example would be if you are using $scope.$watch
There's a good article on controllerAs by ToddMotto: http://toddmotto.com/digging-into-angulars-controller-as-syntax/

AngularJs: Passing "controller as" to a service, is this good practice?

Let's say I have a controller like:
angular.app("myapp",[]).controller("MyCtrl", function (MyService){
var vm = this;
vm.value1 = something();
vm.array1 = somethingElse;
//notice that I pass the whole controller as object to the service.
MyService.getData(vm);
//do something with data...
doWithNewData(vm.elementCreatedByMyService);
}). etc...
Now, to pass the vm itself seems to have sense, because I don't need to pass several values and several controllers call this service.
It seems overkill because, of course, vm has much more than the elements used in the service.
Also, this favors reuse (As I discovered in production).
My questions then: Is this an antipattern or is a valid use of a "controller as" object?
Now, if this is an antipattern, what should do instead?
Thanks in advance...
There's nothing really criminal here to call it antipattern. But there's nothing really good also because it requires the service to be aware of vm, any changes to existing vm properties will effect controller's scope (not necessary in a desirable way).
Now, if this is an antipattern, what should do instead?
Pass local variable to the service and incorporate it into controller's scope when needed?

how does $scope in controllers work and different ways of declaring controllers?

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

From two ways of Creating AngularJS Controllers which should be used and why?

In most demos below method is given
First Method:
function MyCtrl( $scope ){
$scope.someValue = "All your base are belong to us!";
}
Second Method:
app.controller("MyController",funciton( $scope ){
$scope.someValue = "All your base are belong to us!";
});
What are the pros and cons of using either method?
I'll try to give a quick summary each options pros and cons.
1) The following version is often used in examples around the web because it's easy to write. I wouldn't recommend it in real code however, for two reasons. First of all it can break horribly if you minify your code (and you should), secondly you are littering with globals which is generally bad form and encourages sloppy dependencies that are hard to test.
function MyCtrl( $scope ){
$scope.someValue = "All your base are belong to us!";
}
2) The second version you wrote is better. It contains the function on the app which is good, but it can still break from some minifiers.
app.controller("MyController",function( $scope ){
$scope.someValue = "All your base are belong to us!";
});
3) To make it better, lets do this instead. Note that the function is now inside a list with its dependencies. This "double" naming of the dependencies helps angular keep track of things in minified code.
app.controller("MyController", ['$scope', function( $scope ){
$scope.someValue = "All your base are belong to us!";
}]);
4) You can also inject your dependencies after your controller, something like this. This should also be safe from minifiers as far as I know (I haven't used this version myself).
app.controller("MyController",function( $scope ){
$scope.someValue = "All your base are belong to us!";
}).$inject = ['$scope'];
So 3 and 4 are the best ones. They survive minifying and they allow you to easily mock out any dependency when writing tests. As far as I know the difference between 3 and 4 is cosmetic so both should work equally fine. I personally use 3, I think it looks slightly nicer :)
I would highly recommend the second one.
The reason behind this is minification. Angular will try to match the controller's name you call in the templates via ng-controller, e.g.:
<div ng-controller="Controller">
<!-- [...] -->
</div>
Suppose you have a controller like this:
function Controller($scope) {};
and minify it (with some minifiers), you'll get an output like this:
function c(s) {};
Quick EDIT: I checked it with uglify - it will preserve your function name (and you'll be fine), I used a maven based minifier in a project of mine, which actually mangled the method names (I guess I have to replace it)
Your app might just break from that.
Therefore it is recommended to use strings as identifiers for controllers (and injections, etc.) like this:
var app = angular.module("module", []);
app.controller("Controller", ['$scope', function(scope) {
}]);
This will stop a minifier from breaking the app. The reason to put injections like this is as follows:
var app = angular.module('module',[]);
function Ctrl($scope, $location) {
$scope.test = 42;
};
will get minified to (by UglifyJS):
function Ctrl(a){a.test=2}var app=angular.module("module",[])
and Angular will not know that you need the $scope here.
If minification does not matter to you, you can use either one, as the question really just breaks down to maintainability and readability. Also, if you have multiple modules with controllers, the second one will not get you into trouble.
The difference is that the second version defines the controller in your app space. Thus the app.controller call. Difference is that afaik you can only use the controller inside of an ng-app="yourApp" instead of everywhere on the site.
Personally, I like more the 2nd method, because it is easier to review the code and it is more maintainable, those are just my thoughts.But with 1st method you can put it as a controller in other apps.
Here is what I found from
http://www.bennadel.com/blog/2421-Creating-AngularJS-Controllers-With-Instance-Methods.htm
In most AngularJS demos, you will see Controllers being defined as free-standing JavaScript functions:
function MyCtrl( $scope ){
$scope.someValue = "All your base are belong to us!";
}
These functions are then referenced in the View using the ngController directive:
<div ng-controller="MyCtrl">
{{ someValue }}
</div>
NOTE: You should never ever abbreviate "Controller" as "Ctrl". I am only doing that here because this it is what you will typically see in a demo. You should try to avoid abbreviations as much as humanly possible when naming things in programming.
The expression used to define the ngController directive is the name of the Controller in your dependency injection (DI) framework. In an AngularJS application, the dependency injection framework is provided directly by AngularJS. This means that, rather than using a free-standing function, we can use the AngularJS controller() method to define our Controllers:
// Define "MyController" for the Dependency Injection framework
// being used by our application.
app.controller(
"MyController",
funciton( $scope ){
$scope.someValue = "All your base are belong to us!";
}
);
Here, we are defining the controller as an identifier - MyController - and a constructor function. And, once we can do this, we can get much more fine-tuned in how we actually define our constructor function.

Resources