What is the difference between
app.controller("MyCtrl", function($scope, $http){
//...
});
and
app.controller("MyCtrl", ["$scope", "$http", function($scope, $http){
//...
}]);
Even though both gives the same result and no error. In fact the first one makes code clean and less to write. Also it is same in services, directive. Can someone give me a small brief about it.
No functional difference. Using .controller('ctrl',['$scope', function($scope){...} is to allow a minified version to be read correctly.
A Note on Minification - AngularJS
Since Angular infers the controller's dependencies from the names of arguments to the controller's constructor function, if you were to minify the JavaScript code for MyCtrl controller, all of its function arguments would be minified as well, and the dependency injector would not be able to identify services correctly.
We can overcome this problem by annotating the function with the names of the dependencies, provided as strings, which will not get minified. There are two ways to provide these injection annotations:
Create a $inject property on the controller function which holds an array of strings. Each string in the array is the name of the service to inject for the corresponding parameter:
function MyCtrl($scope, $http) {...}
MyCtrl.$inject = ['$scope', '$http'];
app.controller('MyCtrl', MyCtrl);
Use an inline annotation where, instead of just providing the function, you provide an array. This array contains a list of the service names, followed by the function itself:
function MyCtrl($scope, $http) {...}
app.controller('MyCtrl', ['$scope', '$http', MyCtrl]);
Both of these methods work with any function that can be injected by Angular, so it's up to your project's style guide to decide which one you use.
When using the second method, it is common to provide the constructor function inline as an anonymous function when registering the controller:
app.controller('MyCtrl', ['$scope', '$http', function($scope, $http) {...}]);
Adding to wzVang's answer. You can follow your first syntax. i.e
.controller('ctrl', function($scope){
});
without any problem. It is readable. But you should minify your code in production. Then you can use ngAnnotate.
Related
Hi I am new to Angular and JS Frameworks in general. I was wondering if someone could help me decipher some of the notation.
From the docs:
https://docs.angularjs.org/guide/di
Inline Array Annotation
someModule.controller('MyController', ['$scope', 'greeter', function($scope, greeter) {
// ...
}]);
$inject Property Annotation
var MyController = function($scope, greeter) {
// ...
}
MyController.$inject = ['$scope', 'greeter'];
someModule.controller('MyController', MyController);
For my education the $inject method is preferred as it is more exploded. I see three steps: 1) define the function, 2) inject dependencies, 3) attach to parent module.
OK so my questions:
Why are "$scope" and "greeter" listed as parameters to the function and then injected with the $inject? Wouldn't it be one or the other?
someModule.controller('MyController', MyController);
Why is MyController listed twice once as a literal? Is this a type and token thing? Could it just as easily have been:
someModule.controller('MyInstanceOfMyController', MyController);
Thanks for any illumination
For my education the $inject method is preferred as it is more exploded. I see three steps: 1) define the function, 2) inject
dependencies, 3) attach to parent module.
I prefer this notation as well, it reads better.
OK so my questions: Why are "$scope" and "greeter" listed as
parameters to the function and then injected with the $inject?
Wouldn't it be one or the other?
This makes sense, you are telling the injector what to inject, and the function declaration takes these in as usable parameters.
You could change "greeter2 to "newGreeter" in the injector, and you wouldn't need to update the function code in order to use the new module.
someModule.controller('MyController', MyController);
Why is MyController listed twice once as a literal? Is this a type and
token thing? Could it just as easily have been:
someModule.controller('MyInstanceOfMyController', MyController);
Kind of, here you are telling the module
1) What the controller is called
2) Which function defines the controller
These can have the same name, but they don't have to.
Sometimes I see dependency injection in Angular done like:
angular.module('controllers')
.controller('BooksListCtrl', ['$scope', 'Books', function($scope, Books){
Books.get(function(data){
$scope.books = data;
});
}]);
And sometimes it looks like the following without the array, and just passing dependencies directly into the function:
angular.module('controllers')
.controller('BooksListCtrl', function($scope, Books){
Books.get(function(data){
$scope.books = data;
});
});
Is one the right way? Does it depend on whether you are doing dependency injection on a controller vs directive vs etc?
Sometimes I see dependency injection in Angular done like:
angular.module('controllers')
.controller('BooksListCtrl', ['$scope', 'Books', function($scope, Books){
Books.get(function(data){
$scope.books = data;
});
}]);
And sometimes it looks like the following without the array, and just
passing dependencies directly into the function:
angular.module('controllers')
.controller('BooksListCtrl', function($scope, Books){
Books.get(function(data){
$scope.books = data;
});
});
which one is the right way ?
Both
Does it depend on whether you are doing dependency injection on a controller vs directive vs etc?
No
so how are they different ?
Well first form gives you the freedom to handle the dependencies with your own custom name. For example
app.controller('BooksListCtrl', ['$scope', 'Books', function($scope, myOwnBookName){
myOwnBookName.get(function(data){
$scope.books = data;
});
}]);
while second one does not..but both are correct.
Also, you need to be a little cautious while using the first form because you might mistakenly skip a dependency and/or link it with the wrong one.
For example doing something like:
app.controller('BooksListCtrl',['$scope','$window','$rootScope', function(foo, bar){
...
}]);
would be extremely damaging as foo will now point to $scope, bar will point to $window while $rootScope would be undefined. Just keep the order intact and follow proper naming convention.
When you just pass dependency in function, it can not be obfuscated. While you pass an array with function replicating the same dependencies, you can obfuscate the code without breaking the flow
Angular most probably uses the toString method to read out the dependencies in a function passed. When you obfuscate, angular won't be able to read out the argument as dependencies. Now when you pass an array with function as last element using rest of element as arguement in the same order, angular uses array elements to identify the dependencies as they are values and won't be affected by obfuscation.
So as you have wrote in the comment, Yes! it does the same. like :
['$scope', '$location', function (s, l){}] ;
In this angular tries to read array element to inject dependencies not the argument of function.
Prefer the first version you mentioned over the second:
angular.module('controllers')
.controller('BooksListCtrl', ['$scope', 'Books', function($scope, Books){
Books.get(function(data){
$scope.books = data;
});
}]);
This version protects your code from being mangled during minification (even if you're not currently minifying your code you most likely will in the future). The second version you mentioned is perfectly legal, BUT when minified your dependencies such as $scope and Books may very well become a and b and your services obviously will never be injected.
There's also a second way to annotate your dependency injection:
angular.module('controllers')
.controller('BooksListCtrl', BooksListCtrl);
BooksListCtrl.$inject = ['$scope', 'Books'];
function BooksListCtrl($scope, Books) {
Books.get(function(data){
$scope.books = data;
});
}
This makes your dependency injection very clear, and again protects your code from minification mangling.
Just to mention that, I am a very much newbie in Angularjs.
While writing a controller I see I can use
controller('MyController', ['$scope', function($scope) {}])
or
controller('MyController', function($scope) {})
What is the difference between the both ?
Both are same.
When the javascript code is minified, all local variables in the function are changed to smaller variables to reduce size. for example.
function (largevariablename){
largevariablename = 123;
}
will be converted to
function (a){
a= 123;
}
But in case of angular if $scope is minified to s. Then the dependency injection fails searching for s. So angular injector will inject the the string value it finds in the array and inject it instead of the local varaiable in you define it in below way
controller('MyController', ['$scope', function($scope) {}])
So incase if your code in not going to be minified you can use the simple version
controller('MyController', function($scope) {})
This is mainly used for minification. When you minify the js
controller('MyController', function($scope) {})
will be converted to
controller('MyController', function(a) {})
and it will give the error for a is undefined. When you provide the dependency as
controller('MyController', ['$scope', function($scope) {}])
it will map a to $scope and it will work fine.
In fact, you should not use callbacks(Anonymous Functions) directly to define controllers.
You should use separate functions and $inject module to manually identify your dependencies.
controller('MyController', MyController);
MyController.$inject = ['$scope'];
function MyController($scope){
};
Why use named functions ?
This produces more readable code, is much easier to debug, and reduces
the amount of nested callback code.
Why use $inject ?
This technique mirrors the technique used by ng-annotate, which I
recommend for automating the creation of minification safe
dependencies. If ng-annotate detects injection has already been made,
it will not duplicate it.
Also, this safeguards your dependencies from being vulnerable to
minification issues when parameters may be mangled.
This is extracted from well-know John Papa Angularjs Style Guide
what's the difference of defining controller's dependencies in array:
app.controller('IndexController', ['$rootScope', '$http', function($rootScope, $http) {
//some cool stuff
}]);
and injecting them right into the function like this:
app.controller('IndexController', function($rootScope, $http) {
//some cool stuff
});
Lot of posts and tutorials use the shorter version, so I'm wondering if there's any advantage of doing it the first way.
Thanks!
This is necessary if you use some minification tools such as uglify. These kind of tools change the name of the variables, thus, for example:
app.controller('IndexController', function($rootScope, $http) {
//some cool stuff
});
Becomes something like:
randomVariable.controller('IndexController',function(a, b){});
And a and b are not your dependencies.
In the other case, the minified code becomes something like:
app.controller('IndexController',['$rootScope','$http',function(a,b)
Here a and b are passed as arguments from two strings that are values and hence they cannot be modified by the minification tools
Regarding controller definitions. What is the difference between this...
angular.module('myApp', ['ui.bootstrap']);
function CarouselCtrl($scope) {
...
}
and this...
var myAppModule = angular.module('myApp', ['ui.bootstrap']);
myAppModule.controller('CarouselCtrl', function($scope){
...
}
It seems that both of them get access to ui.bootstrap.
How is the first CarouselCtrl function connected to my angular.module?
The first one is a global function. You should not be using it. It is "connected" to your module because it is connected to everything.
The second one is a controller declared in a module. this is fine and it's a usual approach. You can have a module with directives, a module with services, etc. More about organizing your application
The safest option is using annotations:
var myAppModule = angular.module('myApp', ['ui.bootstrap']);
myAppModule.controller('CarouselCtrl', [ '$scope', '$http', function($scope, $http){
...
}]);
As Golo Roden points out in the comments, you can avoid global variables by referencing the controller like this:
angular.module('myApp').controller(...);
This way the application can be minified without breaking, as explained in the manual https://docs.angularjs.org/guide/di
the reason is that dependency injection looks up components by name. you can minify the name of a function but values in arrays will never be altered. The order in the array is important. it matches 1-1 with the parameters in the function.