I usually declare one controller this way:
.controller('myController', function($scope,/*other dependecies go here*/){
// controller definition
};
However in some examples (including one from AngularJS's official documentation) I found something like:
angular.module('controllerExample', [])
.controller('SettingsController2', ['$scope', SettingsController2]);
function SettingsController2($scope) {
// controller definition
};
or simply (which is equivalent, I guess):
angular.module('controllerExample', [])
.controller('SettingsController2', ['$scope', function(){
// controller definition
}
]);
Now, I don't understand what is the actual difference between snippet 1) and snippets 2) and 3)
Also, I don't understand why sometimes the same dependency is both outside the function definition and in function parameters (like snippet 3) ) but outside is without $ and inside is with (sorry I can't find an example now. But I'm sure I had this situation).
Thank you in advance
The array syntax is to prevent angular from breaking when the code goes through a minifier. If you are not minifying your javascript, there really isn't a big difference other than you get to type more/less. Angular reads in these functions as a string and processes them. Some minifiers screw that up, so that weird syntax is the current solution.
#jwimmer's answer is correct but I want to offer one more possibility. You can clean up the syntax a bit and keep your code minification safe using $inject.
someCtrl.$inject = ['$scope', 'someDependency'];
function someCtrl($scope, someDependency) {
...
}
angular.module('someApp')
.controller('someCtrl', someCtrl);
Related
I have been coding in Angular for a little bit of time now and I have created Modules, Controller and Services so far but I recently just came across a piece of code which I am just not able to understand. It is someone else's code and I think author has tried to define a service but not like I have created. Normally when I create a service it looks like below:
app.factory('portabilityService', [
'$resource', '$state', '$rootScope', function ($resource, $state, $rootScope) {
return { //definition };
}
]);
To me it is simple specify service name as the first argument inside Factory followed by all the dependencies and there you go.
Now, I came across some other code which looks like following:
(function () {
/*
* Manages which samples have been selected
*/
'use strict';
angular.module('maintenance.portability.module')
.factory('selectedSamplesSvc', service);
service.$inject = [];
function service()
{
//other function definitions
};
})();
Now, this raises a lot of questions:
First of all, is this really a service?
If yes, what is service.$inject = []?
Where should I add the dependencies?
What is the purpose of the constructor service() here?
Is it just a different way to create a service or there is a specific reason why we should define a service in this particular way?
I'll try to address your questions in order:
First, yes, this is definitely a way to declare a service. It's not entirely far off from what you are normally used to using.
The normal syntax for declarations in angular is:
typeOfDeclaration('stringNameOfDeclaration', functionDeclaration);
function functionDeclaration(){..};
In JavaScript, a function is an object, so an anonymous function can be used in place of the functionDeclaration, for example:
typeOfDeclaration('stringNameOfDeclaration', function(){..});
This inline declaration is usually easier to write when you are only making a single declaration, and is the defacto standard for most tutorial examples.
Note that these rules apply to all angular components (providers, filters, directives, controllers, etc.)
By declaring the function as a separate object rather than inline, the declaration and the function are more easily managed. You could, in theory, put the function itself into a different file (though this is not common). Also, if you are declaring multiple functions, this syntax allows you to group the declarations together and the functions together, which is mostly a matter of preference and coding style.
The optional array of dependencies in your example are a way to manage Dependency Injection in cases where the code will be minified. In this case, another alternate DI method is used, service.$inject = [];. This array can be used instead of the inline array, i.e. service.$inject = ['$resource', '$state', '$rootScope']; Again, this gives you a way to group your declarations in one place, your dependencies in another.
All the answers boil down to this: They're equivalent with equivalent definitions of the function passed to .factory.
Yes, it's a service (based on the prior statement)
$inject is an alternative to your [ names..., function(dependencies...) {...}] syntax
The same way just now your function definition is separate.
It's the function you pass anonymously
It's preference for the most part but explicit $inject is beneficial for minimizing
For additional considerations on the matter (in part) and overall good reading give this style guide a look.
What is better when creating a controller in AngularJs:
1-
angular.module('myApp')
.controller('MyController',['$scope','dependencies','myService', function($scope, dependencies, myService ) {
}]);
2-
angular.module('myApp')
.controller('MyController', function($scope, dependencies, myService ) {
});
Performance wise, the first is technically better, although that cost is probably negligible. If you do it the second way, angular literally calls the .toString() function on your controller function, and then parses the string to determine the dependencies. So you can either declare them yourself, or angular will parse your function as a string to determine them.
As a developer, I find it easier to read and write the second version. Just be aware that you have to change things to the first form if you plan on uglifying/minifying your code. Some tools will do this for you automatically (ngAnnotate, for example), so that you can write it the 2nd way, but have it deployed the first way.
With this method you have the advantage of function hoisting , function name for debugging , ability to mutate $inject;
also easier to reason about & debugging.
function myController(){
}
myController.$inject = ['$scope','dependencies','myService'];
angular.module('myApp' ,myController);
What is the difference between these 2:
angular.module('myapp' ,[])
.controller('MyController', function($scope){...});
and
angular.module('myapp' ,[])
.controller('MyController, ['$scope', function($scope){...})];
This is quite complicated for those who new to AngularJS like me. The syntax is too different from Java and C.
Many thanks.
There's nothing difference between them. Both code works same way. But if you use first code and when you minify the code then it will confuse.
Look for an example:
.controller('MyController', function(a){...});//$scope is changed to a
And your code won't work as angularjs code uses $scope variable as it doesn't take first, second, third, and so on parameters.
So, the second code is safer than first as if when you minify the code, it still takes same variable i.e. $scope.
Look for an example:
.controller('MyController', ['$scope', function(a){...})];//a refers to $scope
So, the above code works fine when you minify the code as $scope is injected in place of a. So, if you pass multiple parameters then ordering matters in this example. Look at the following:
.controller('MyController', ['$scope','$timeout', function(s,t){...})]; s is injected as $scope and t is injected as $timeout. So if you change the order of them like ['$timeout','$scope', function(s,t){...})] then s is $timeout and t is $scope. So, ordering matters in this example but in your first example code ordering won't matter as name matters like $scope, $timeout.
There's also another way to inject variables if you use your first example code like below:
MyController.$inject = ['$scope'];
For multiple parameters,
MyController.$inject = ['$scope','$timeout'];
So, there are mainly three kinds of annotation:
Implicit Annotation - your first example code
$inject Property Annotation - the $inject method
Inline Array Annotation - your second example code
The second is minification safe.
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 PhoneListCtrl controller, all of its
function arguments would be minified as well, and the dependency
injector would not be able to identify services correctly.
Source
I'm kind of a big angularJS newbie and I'd like some highlights concerning dependency injection.
I've done some research and here is what I understand so far.
I have 2 service files (using factories) :
-mogService.js
angular.module('anglober.services').factory('mogService', ['$http', function($http) {
var mogService = {};
//mogService code here
return mogService;
}]);
-modalService.js
angular.module('anglober.services').factory('modalService', ['$modal',
function ($modal) {
//modalService code here
}]);
One controller file :
-mogCtrl.js
angular.module('anglober.controllers').controller('mogCtrl', ['$scope', 'mogService','modalService', function ($scope, mogService, modalService) {
//code using mogService and modalService parameters
}]);
As I understand it, the dependency injection is done by passing my services as parameters of the function parameter in my controller declaration, the array of string is here so that after minification, angular still knows which variable is what.
However, the modalService variable is undefined when I test my code. The mogService is recognized alright though (only if I remove any call to the modalService variable).
What am I doing wrong ?
I've read things about using $inject, which is the better practice and why ?
I'm declaring modules in the app.js as follows :
angular.module('anglober.services', ['ui.bootstrap']);
angular.module('anglober.controllers', []);
var app = angular.module('anglober', ['anglober.controllers', 'anglober.services', 'anglober.directives']);
Is this good practice ? Declaring modules and their respective dependencies in one file then only use "getters" without the dependencies array parameter in module files ?
Thanks for your time.
Three steps that work for me (plunkr):
1. Be sure you define a module's dependencies only once.
Indeed, check that angular.module('anglober.services', [...]); is indeed called only once with the second argument.
At the same time, be sure to call these lines before the actual services/controllers /... definitons.
2. Wire every dependency
You should add 'anglober.services' dependency to 'anglober.controllers': the last requires modalService which requires $modal, it may help angular anyway.
3. Add possible missing lib requirements, in the right order
First jQuery, then angular, bootstrap and eventually bootstrap.ui and your modules.
Both of these work, but what is the actual difference between each implementation? I'm sure there is a logical reasoning behind each method, and I wish to be enlightened.
angular.module('app').controller('GeneralCtrl',
function($scope, $location, exampleService) {
$scope.variable = exampleService.getExampleVariable();
}
);
angular.module('app').controller('GeneralCtrl',
['$scope', '$location', 'exampleService', function($scope, $location, exampleService) {
$scope.variable = exampleService.getExampleVariable();
}]
);
What is the actual difference between these? Where would you use them differently? Why?
Answer: Turns out the latter is minification safe as minifiers rename parameter names, so dependencies cannot be inferred from their names, and so must be annotated.
This is what Angular calls "inline notation" for dependency injection (see http://docs.angularjs.org/guide/di for a whole lot of detail).
In the example you gave, the ng-controller directive is actually doing the work behind the scenes, of hooking up $scope, $location, and exampleService into the variables you're providing to that first function. It's doing this by default based on variable names (that is, it assumes that a variable called $scope is asking for the $scope dependency).
That said, when you minify your code, the variable names get chopped down also (ie, $scope might become a). When that happens, Angular now doesn't know what you meant by the variables anymore.
One option is to add
GeneralCtl.$inject('$scope', '$location', 'exampleService')
Another is to provide those strings like you did in the second example. This makes sure that even if the variable names get changed around, you're telling Angular what they were supposed to represent, and it knows how to set them properly.