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.
Related
One of the frustrations I face with AngularJS is the variety of styles that are used in examples. I have seen 4 different ways to declare and add AngularJS elements to a module (including different ways to declare the module). In another question I asked about using a global variable vs. directly declaring the module. Now I would like to know what are the advantages/disadvantages to using various styles to add elements to the module. (I will not include the examples that declare a global variable for the module, as that style has been discounted as a 'bad practice')
Assume the module is declared in file myMod.js as:
angular.module('myMod', [
// Angular modules
'ui.router'
,'ui.bootstrap'
,'ngResource'
,'ngStorage'
]);
Now I want to add a controller to the module, I have seen:
(assume each example represents the entire contents of a file named: myController.js)
option A:
angular.module('myMod')
.controller.('thisController',['dependencyA','dependencyB',
function(dependencyA, dependencyB){
....stuff to do
}]);
option B: just adding 'use strict'
'use strict';
angular.module('myMod')
.controller.('thisController',['dependencyA','dependencyB',
function(dependencyA, dependencyB){
....stuff to do
}]);
options C: wrapping the whole thing in an anonymous function as:
(function(){
'use strict';
angular.module('myMod')
.controller.('thisController',['dependencyA','dependencyB',
function(dependencyA, dependencyB){
....stuff to do
}]);
option D: Declaring a named function rather than an anonymous function in the controller declaration as:
(function(){
'use strict'
angular
.module('myMod')
.controller('thisController',thisController);
thisController.$inject = ['dependencyA','dependencyB'];
function thisController(dependencyA,dependencyB){
...stuff to do
}
Similar diverse examples exist for adding factories, services, directives, etc. into a module. As best I can tell these are different styles for accomplishing the same goal. Which techniques represent 'best practices' and 'why'?
(I am not wanting this to turn into an 'opinion piece' please offer 'objective' reasons to select a style.)
As for 'use strict', this has nothing to do with AngularjJS per se. It is a Javascript directive that enforces strict mode which prohibits the use of undeclared variables in Javascript.
Immediately-Invoked Function Expression (IIFE) that wrap angular code prevent the leaking of variables into the global scope.
As for declaring a named function, in my opinion this leads to much clearer code and is my preferred way.
They all perform the same job, I personally use the named function approach. But you can combine them if you want.
angular
.module('myMod')
.controller('thisController',['dependencyA', thisController]);
thisController.$inject = ['dependencyB'];
function thisController(dependencyA,dependencyB){
...stuff to do
}
I use TypeScript so my controllers look something like this.
export class thisController
{
static $inject = ['DependencyA'];
constructor(private _dependencyA: DependencyA)
{
}
}
angular.module('myMod').controller('thisController', thisController)
I am doing it this way.
Method 1:
var app = angular.module('MyModule', ['ngDialog']);
app.controller('MyController', function ($scope,ngDialog) {
///
});
but i see a lot like the below kind in articles
Method 2:
app.controller('MyController', ['$scope', function ($scope) {
///
}]);
Please help me understand why is $scope mentioned twice in method 2.
Is method 1, a good practice. If not, in what cases will it fail.
Method 2 is used to prevent minification bugs. In Production when you usually minify your JS/CSS files, the variables' names change to reduce bytes and make the files lighter.
AngularJS relies on DI, which means that it knows which service/provider to inject to your controllers/services according to the name. If it sees $httpProvider, it knows to inject $httpProvider. Once minifaction takes place, the naming will change from:
app.controller('MyController', function (a,b) { //a, b is the change
///
});
Or something of that sort.
Using Method 2, you specify the names as strings, and using those strings AngularJS knows what to inject despite the fact that the minification changed the variables' names.
You can read more about this here.
The recommended way of declaring Controllers is using the array notation:
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
...
$scope.aMethod = function() {
...
}
...
}]);
Dependency Annotation
There are three ways of annotating your code with service name information:
Using the inline array annotation (preferred)
Using the $inject property annotation
Implicitly from the function parameter names (has caveats)
Among These three,Using the inline array annotation is preferred approach.And
the last is simplest way to get hold of the dependencies is to assume
that the function parameter names are the names of the dependencies.
Advantage of implicitly from the function parameter names approach is that there's no array of names to keep in sync with the function parameters. You can also freely reorder dependencies.And disadvantage is If you plan to minify your code, your service names will get renamed and break your app.
Source: this
I started learning angularjs and I see 2 types of module uses and I cant understand when to use this and when this:
example1:
var app = angular.module('app', []);
app.factory('Comment', function($http) {
}
app.controller('mainController', function($scope, $http, Comment) {
}
or
example2:
angular.module('commentService', [])
.factory('Comment', function($http) {
}
angular.module('mainCtrl', [])
.controller('mainController', function($scope, $http, Comment) {
}
var app = angular.module('app', ['commentService','mainCtrl']);
sometimes I see module declarion in each file(services factory controllers and so on)
and sometimes I see using the app module in those files, what is the right way? and why both of them works?
First and foremost, if you're concerned about app organization, read the discussion on the yeoman-generator-angular issue board from about a year ago. There's way more wisdom there than you could feasibly expect to get in a SO answer.That said, I'll try to provide an answer that's more pertinent to your specific concern, and (marginally) more concise.
DO NOT make a module for a single controller like angular.module('MainCtrl',[]).controller('MainCtrl'), or even a set of controllers who are only related in that they are all controllers:
angular.module('appCtrl', [])
.controller('appleController', function ($scope) {})
.controller('orangeController', function ($scope) {})
.controller('unicornController', function ($scope) {})
;
Why is this a bad idea? First, by definition, it's categorical, not modular; modules are groupings of system components which are related topically, not conceptually. When you're building a car, you don't put in all of the nuts and bolts at once. You put in the nuts and bolts that hold together the module that you're building. Controllers are like nuts and bolts. An engine is like a module.
Second, now you have to inject the appCtrl module anywhere that you want access to a controller. That's just a mess for developers to have to deal with; they're always digging through the code trying to find "whatever that module with that one thing in it" was, or they'll just repeat code all over the place.
Dependency Injection in AngularJS is less a rule than a (clever and awesome) string manipulation hack, and JavaScript has no "namespacing" system in the classical sense. Creating modules like app.products or app.cart is more for the developer's convenience and/or controlling the release cycle than making the program "work".
For these and other reasons, I caution developers against "Premature Modularization". If you're writing something app-specific---that is, you won't be reusing it right now in another app---why not just attach it to your app module? Then you have access to it anywhere in your app that you want it. (There are of course complexities that might cause you to change this, but if/when those do arise that's when you modularize).
Structure your directories by feature (Angular conventions do condone BDD, after all):
|-app/
|-|-cart/
|-|-|-CartItemsModel.js
|-|-|-OrderRepository.js
|-|-|-cart.html
|-|-|-add-item-modal/
|-##some more cart stuff
|-|-checkout/
|-|-|-confirmation/
|-|-|-|-confirmation.html
|-|-|-|-confirmation.less
If you're writing feature files or getting acceptance criteria from your employer, you can even model your directory structure directly after those features or requirement sets. That makes everything smooth from defining the scope of an iteration through documentation through revisiting code at a later time.
Both example work. But for instance with the example 2, this syntax can be used for separation of concern. You may need a module that is responsible for providing services which gives you function for Rest calls. Or another module that package some directives.
It's generally considered good practice to segregate your modules into different files. This will ensure that you are practicing good code control, and gives your code a greater degree of portability and debug-ability. Instead of declaring modules in the same file, declare them in different files with their module name.
It's good practice to segregate your files based on their module-controller relationship -- that is, each controller should have its own file, like this:
\scripts\controllers\
- - main.js
- - comments.js
Then, inside your main.js file, you'll start off with the controller declaration:
//main.js
angular.module('app')
.controller('MainController', function ($scope, $http) {
// Controller-scope stuff here
});
Finally, inside your comments.js file:
angular.module('app')
.controller('CommentsController', function($scope, $http, $routeParams) {
// Comment controller code
});
One way to help with organization right off the bat is to organize your files is with a seed template, like Angular Seed.
Just remember that you want to keep your module('app').controller('whatever') inside whatever.js, and any other .factory('forWhatever') (like in your example) should be contained with that parent .controller('whatever') inside the whatever.js file.
I have a very small number of functions that I need to use like this:
data-ng-disabled="_isEmpty(grid.view) || view != 'preview'"
What I did was:
$scope._isEmpty = _.isEmpty;
so that the _isEmpty is actually the lodash function.
Is this a reasonable thing to do? Also if so then where would be a good place for me
to code the above line? Should I code that in my appController. Also should I attach
the ._isEmpty to $scope or $rootscope? I have heard people talking about making a service and then injecting this. But for a few lines of code this seems overkill.
It all depends on where this code is required. If it is heavily reliant on, or required by a particular data object or view, then it most likely belongs in a controller. If inside a controller, $scope should be used by any value you want to reference in a view.
If however, you are writing generic functions used throughout your application, then they should be put in something like a service, and injected where required. Most of the time if you find yourself using $rootScope, the code should probably be in a service. Services aren't really overkill, as you can see below:
angular.module('myapp.services.something', [])
.factory('myService', [function () {
return {
myFunc: function (someArg) {
console.log(someArg);
}
};
}]);
You could put any number of generic helper functions for example in a service like this, and inject them into any controller that requires their use.
Though generally not recommended, I could see this kind of problem solved with putting the functions into the rootscope. Then putting the line $scope._isEmpty = _.isEmpty; in every controller would not be necessary anymore. A far better way for me would be to recode the utility functions into directives, even if involves some coding. Another way to solve the problem is to use services.
I've been reading through the tutorial, dev guide, and practicing on my own, but I'm having trouble piecing everything together in my mind with regard to dependency injection.
Question: Within the first code snippet in the linked page below, why is the name of the "service" located in front of $inject and why is the parameter of the service used here again? Or better yet what concepts am I lacking in understanding? I'd like to be able to piece it all together in my head step by step, but I'm still trying to understand how exactly even the globally defined "services/functions" can be written this way.
http://docs.angularjs.org/guide/dev_guide.services.understanding_services
So in that code snippet is injecting the $location service into MyController. So MyController depends on $location so it declares the dependency and its owns the dependency declaration.
Here is the code commented:
// declaring a Controller function
var MyController = function($location) { ... };
// $location service is required by MyController
MyController.$inject = ['$location'];
// Then register the Controller in the module.
// The module is the container that performs DI on the objects within it.
myModule.controller('MyController', MyController);
Typically though you'd do the following to declare the Controller and it's dependencies in one shot that's cleaner. The dependencies are strings at the front of the array before the final function which is the controller being registered. Here is the simpler definition:
myModule.controller('MyController', ['$scope', '$location', function($scope, $location) {
$scope.someFunction = function() {
// do something with $location service in here
};
}]);
Keep in mind this:
"...even the globally defined "services/functions"
The whole point of DI is to not define things globally because global definitions create coupling that make it hard to reuse major portions of your system (ie you can't break apart the system without instantiating the whole thing). Dependency Injection separates the dependency (ie MyController depends on/uses $location service) from where it finds that reference. Beginner developers, and some dense senior devs quite frankly, typically just define things globally and that's how everything gets a reference to their dependencies. DI allows code to simply declare its dependencies so its dependencies can be given to the code by an external entity instead of the code assuming where to get it from. Often this is called the Hollywood Principle - Don't call us we'll call you.
It looks like you're lacking a strong understanding of Dependency Injection in AngularJS.
Once you define a service, it then needs to be injected inside to the controller that is going to use it. The two code samples on that page show the two different methods of injecting the service into the controller.
I'd suggest you look at the docs: AngularJS: Dependency Injection