Why wouldn't you use explicit annotations when defining controllers in AngularJS? - javascript

I am new to AngularJS and learning about the two styles of writing controller functions. It seems as though the only reason someone would not use explicit annotations is to save time, which doesn't seem like a good reason. And being able to minify/obfuscate code seems like a requirement I would want to keep in any application.
Also note that I am not asking which is better or asking for a debate. I am asking for what reasons (or in what situation) it would be more beneficial to not use explicit annotations.
Example of what I'm talking about:
module('myApp').controller('MyController', function($scope) {});
vs.
module('myApp').controller('MyController', ['$scope', function($scope) {}]);

The inline array annotation is simply a workaround over Javascript limitations to allow Angular code to be minified and not to stop working. But it isn't a great solution because if forces you to duplicate your code. And we all know how bad duplicate code is. Angular documentation itself acknowledges that:
When using this type of annotation, take care to keep the annotation
array in sync with the parameters in the function declaration.
It's way too easy to add a new dependency and forget to add the corresponding annotation. Or to reorder the arguments and forget to update the list of annotations. Trust me. Been there, done that.
Fortunately there are tools developed by smart people that take that burden off our shoulders by taking care of annotating the code automatically. Probably the most known is ng-annotate, as mentioned by #pankajparkar. All you have to do is plug it into your build process and your code will be correctly annotated.
To be honest, I find it really odd that Angular documentation recommends against following this approach.

Obviously You need Array annotation of DI while doing JS minification,
If you don't want minification of JS files then you can continue
function pattern.
Refer this Article which has good explanation about what you want.
If you don't want to include array annotation of Dependency injection then simply you could use ng-annotate library. (As you are saying, its not bad pattern thought you can avoid it by ng-annotate)
Which does do convert your code to array annotation of DI while minifying js files
Only you need to add ng-strict-di attribute where ever you declared your ng-app directive.
<div ng-app="myApp" ng-strict-di>

I suppose the one situation where it would be useful and indeed necessary to use the annotations would be if you didn't want anyone to minify your application code.

Using direct arguments
when you pass argument to controller function, In this mechanism, you will pass arguments and angular will recognize
Ex.
module('myApp').controller('MyController', function($scope) {});
module('myApp').controller('MyController', function($scope,$http) {});
OR
module('myApp').controller('MyController', function($http,$scope) {});
In the second and third example, place of $scope and $http is different, but they work without error. This means angular recognizes which is $scope and which is $http.
Now consider you developed an web application and you are going to deploy it. Before deploy will minify your javascript code to reduce size of your js file.
In minification process, each variable will get shorten as like $scope may become a, and angular can not recognize 'a'.
Using array method
This is the standard mechanism, when you pass an array , the array elements are strings except last element, the last array element is your controller function.
You must need to specify the order of each argument in array as string and you can pass that variable in function, here you can provide any variable names as they are just alias.
ex.
module('myApp').controller('MyController', ['$scope',function($scope) {}]);
module('myApp').controller('MyController', ['$scope','$http',function(myscope,newhttp) {}]);
Now in this mechanism, if you use any minifier to minify this js, it will minify and change myscope to any other name say 'b', but it will not touch $scope as it is a string, and you dont need to worry as b is just a alias for $scope.
This is recommended, but if you are using grunt/gulp for minification, you can check these
ng-di-annotate
ng-annotate

The only real reason is that it's faster when mocking an application.
This is a leftover from early on in Angular, when they had a few features that they used for 'showing off' how easy it was to make an Angular app. Another example is how Angular used to look for controllers that were declared globally on window; they removed that 'feature' in 1.3. This changelog best explains why.
It's a fun little gimmick, and it helps ease new developers into the world of Angular, but there's no good reason to use it in a production app.

Related

Difference between using Angular $scope dependency and no dependency

There is something that i don't understand with Angular.
I'm new to Angular, and i don't remember where but the tutorial that teached me used this syntax do apply properties to a controller's scope :
app.controller('someCtrl', function(){
this.variable = "hey!";
});
So, i was starting my web app, everything was fine, then i wanted to add some socket.io interactivity with my node.js server. So i was looking for some tutorials on how to make them work together i was confronted to this syntax :
app.controller('someCtrl', ['$scope', function($scope){
$scope.variable = "hey!";
}]);
I thought it was weird, so i looked into Angular's articles about dependency injection and scopes, i found that it was actually the way everyone is doing it... I also started to see that it allows you to interact with $rootScope and other stuff, which is i guess the way to make controllers interact with each other. But i still don't see the difference between the two. Is the first one one which is used to teach people the basics of angular in order to easily introduce them to the scope and dependency injection concepts ?
Thanks in advance for your answer.
Yes, that is confusing as hell and I wish the Angular guys would only use the second. The first one is easier to read and understand for any JS developer, however the docs used to state (AFAIK, that is gone from the docs now):
Previous versions of Angular (pre 1.0 RC) allowed you to use this interchangeably with the $scope method, but this is no longer the case. Inside of methods defined on the scope this and $scope are interchangeable (angular sets this to $scope), but not otherwise inside your controller constructor.
Since some versions, the second syntax (which injects $scope via dependency injection) is typically used, even if it is somewhat frightening to newbies, what with the array in the function variable list (which is needed for minification) and all.
The situation gets worse, though, because lately this makes a comeback in slightly different form, the "controller as" syntax:
HTML
<div ng-controller="MainController as main">
{{ main.someProp }}
</div>
Javascript
app.controller('MainController', function () {
var model = this;
model.someProp = 'Some value.'
});
So, most likely what you read is the "controller as" syntax that is currently pushing back more and more the second, dependency injection form. You can differentiate it from old examples if you look at the HTML to find XxxController as yyyy.
Typically, you don't work with this all the time in your controller's functions since the scoping of this in Javascript can easily introduce bugs. Therefore it is preferable to assign this to some local variable immediately and then work with that variable (model in my example) like you would with $scope.
TL;DR: work with the "controller as" syntax to be future-proof, but know until recently, the best practice was injecting $scope.
Basically, You should directly inject the $scope as a dependency to avoid minification problems.
When doing a minification, $scope will be translated into e and Angular will not know how to use e itself.
var app=angular.module("myApp",[]);app.controller("mainController",function(e){e.message="OH NO!"})
When directly injecting the dependency as you shown, $scope will not be renamed in any other way, so Angular will know how to handle it.
Take a look at this article on Scotch.io
I hope I've been helpful.

Components and directives in angular 1.5

The big feature changes in Angular 1.5 are surrounding the support of components.
component('myComponent', {
template: '<h1>Hello {{ $ctrl.getFullName() }}</h1>',
bindings: { firstName: '<', lastName: '<' },
controller: function() {
this.getFullName = function() {
return this.firstName + ' ' + this.lastName;
};
}
});
While this is all good, I am not sure how this differs from directives.
What are the benefits of using components over traditional custom directives? And are components in Angular 1.5 and Angular 2 the same?
The .component DOES NOT replaces .directive like #rek Żelechowski said.
So..
There’s nothing you can do with .component() that you can’t do with .directive().
It aims to simplify the way we create “components” – which roughly means UI directives.
When can/should you use it?
Clearly there are a few cases where you can’t/shouldn’t use it:
If you need the link function (though you rarely should)
If you want a template-less directive, e.g. ng-click that doesn’t have a template or separate scope
For all your other directives, this should work. And because it saves on boilerplate and less error-prone it’s nicer to use.
Despite of all new goodies, .component() can’t fully replace .directive().
The .component is now preferred way of writing code because it favors good practices and gives developers ability to write code like in angular 2 (similar to Web Components). Basically, when you write code using component, upgrading to angular 2 will be easier. Functionalities remains almost the same. You should use .component always when it is possible.
Changes (extract)
component is declared using object instead of function
simplified isolated scope using binding property
components are always with isolated scope
some bad practices will not be possible
simpler, easier to understand configuration
lifecycle hooks: ($onInit(), $onChanges(changesObj), $doCheck(), $onDestroy(), $postLink())
Awesome article is here:
https://toddmotto.com/exploring-the-angular-1-5-component-method
When not to use Components (from docs):
for directives that need to perform actions in compile and pre-link functions, because they aren't available
when you need advanced directive definition options like priority, terminal, multi-element
when you want a directive that is triggered by an attribute or CSS class, rather than an element.
I believe, that the best description you can find is official guide: https://docs.angularjs.org/guide/component. It covers all changes, reasons for changes and gives you deep understanding of the components.
EDIT 01-2020:
I don't work on ng1 code anymore since at least a year
At the point of writing response (01-2017), impression that they are going to replace directives in most scenarios was correct. I removed a word "replaced" from the answer in 06-2017, because it is was indeed misleading at that point in time. However, since 1.5 you should still prefer components over directives when possible.
Actually, you should prefer not to use AngularJS at all. It is now in LTS and basically, only errors will be fixed. No new features. Also, LTS ends on 01-07-2021.
https://docs.angularjs.org/misc/version-support-status#long-term-support
PS. Using component instead of directive makes the code easier to port to ngx in the future.
Directives are NOT replaced, they just have been changed for lots of various reasons that might be a bit too much to get into here. The angular docs explain them pretty well, so you can start looking at the documentation there:
https://docs.angularjs.org/guide/component
To get a better idea of what the differences between directives and components are, I find that its better to reference the Angular 2.0 documentation. Angular 1.5 gave us a bridge to 2.0 that 1.4 and prior did not have. One of the bigger changes is removing $scope, another is providing Components as a way to build things (which is HIGHLY used in Angular 2.0).
All in all the very meat of the change is that it prepares the 1.X world to migrate to the 2.X world. In that world there are Components (which are element level directives at their heart), structural directives and attribute directives. See the below links to help understand each (along with the link provided above).
http://learnangular2.com/components/
https://angular.io/docs/ts/latest/guide/structural-directives.html
https://angular.io/docs/ts/latest/guide/attribute-directives.html

Why would you ever use the $rootScope?

Ok so I was reading here
basically when I have this
MyApp = MyApp || {};
MyApp.settings = {
isFooEnabled: false
}
if I use the rootscope and want to check if isFooEnabled I have to inject the rootScope into whatever object I want to do the check.
How does that make sense?
What is the advantage of using $rootScope.isFooEnabled over using straight standard javascript MyApp.isFooEnabled?
what is better for what?
when should I use one over the other?
The $rootScope is the top-most scope. An app can have only one $rootScope which will be shared among all the components of an app. Hence it acts like a global variable. All other $scopes are children of the $rootScope.
The rootScope's variable is set when the module initializes, and then each of the inherited scope's get their own copy which can be set independently.
NOTE:
When you use ng-model with $rootScope objects then AngularJS updates those objects under a specific $scope of a controller but not
at global level $rootScope.
The $rootScope shouldn't be used to share variables when we have things like services and factories.
Finally, Angular FAQ says this at the bottom of the page: "Conversely, don't create a service whose only purpose in life is to store and return bits of data." See from here.
Actually, I would argue that you shouldn't use $rootScope in this case, you should create a separate service (or factory) that stores your settings, however, the usage and reasons are the same.
For simply storing values, the primary reason is consistency. Modules and dependency injection are a big part of angular to ensure you write testable code, and these all use dependency injection so that unit tests can be written easily (dependencies can be mocked). Whilst there are not many obvious gains from injecting a simple object, it's consistent with the way more complex code is accessed, and there is a lot to be said for that. On a similar note, if you were to upgrade your settings object to fetch data from the server (e.g. for environment specific settings), you might want to start unit testing that functionality, which you can't really do properly without modularising it.
There is also the (frankly weak) namespacing argument - what if another library you import uses window.MyApp?
TL;DR: It's a strongly recommended best-practice. It might seem a bit clunky now, but you'll benefit from doing it in the long run.

When to use $injector in AngularJS

As I'm parsing through AngularJS documentation, I thought I would post this to get some other opinions.
My specific scenario is that I have settings I wish to change on an injectable using the run method of my module. I have a couple of different ways I can access the injectable and wasn't sure if there was a discernible functional advantage to using one over the other. Or do they boil down to essentially the same thing.
Say for instance my module is defined as thus:
var app = angular.module('MyModule', ['some.Third.Party.Module']);
Now consider that there is a factory in the third party module with variable that needs to be set. This can be accomplished by doing the following:
app.run(['some.Third.Party.Module.Factory', function (theFactory) {
theFactory.someVariable = 'foo';
}]);
An alternative method would be:
app.run(function ($injector) {
var theFactory = $injector.get('some.Third.Party.Module.Factory');
theFactory.someVariable = 'foo';
});
Is one method better than the other? Maybe there is a third option I haven't considered yet?
You are actually using the three different methods (to my knowledge) Angular provides for injecting dependencies.
Angular can identify a dependency solely through the name of a function parameter. You are doing this here when you inject $injector.
app.run(function ($injector) { ... });
The above is quick and easy for development but you can run into problems when minifying code as variable names can change.
For production, and generally a good practice in development is to use annotations as you already have in your second code example for some.Third.Party.Module.Factory.
app.run(['$injector', function ($injector) { ... }]);
The third way I know of is to use $injector directly.
This is useful for unit testing and if perhaps you wanted to conditionally switch up which dependency is injected.
It provides dynamic annotation rather than static.
The former is effectively shorthand for the latter, but keep in mind that referencing $injector directly will cause problems if you minify the code since that variable will be renamed. Your first usage is minifaction-proof.
I would generally stick with the first usage, but you could also use the $inject annotation like so:
var MyController = function($scope, greeter) {
// ...
}
MyController.$inject = ['$scope', 'greeter'];
someModule.controller('MyController', MyController);
This makes sense if you want to add properties to MyController's prototype and still use it as the controller definition.
I'm really not sure of a scenario where you would need to use the $injector directly unless you were doing something very fancy.
Also keep in mind the difference between the run and config methods. The latter lets you use providers which allow you to configure services used in the run method (and when they are injected).
I think there is two cases when you need to get service/factory/whatever via $injector:
1) you have circular dependency, but you sure that everything will be fine.
2)you need to get something from "angular-world" from outside of it.
upd: also case provided by #Explosion Pills looks interesting.

Best way to handle configuration in AngularJS

Right now I have a service that runs and is injected into almost every single controller that provides a different API version string and URL string for requests based on $location's information as to whether the app runs on localhost or the website URL. Can something be set up to do something like this instead?
angular.module('app', [])
.config(['$location', function($location) {
// create app constants here and provide them globally somehow without requiring injection
// something like constants.api, module.constants.api, or pretty much anything
// else that exposes the keys set here in a developer-friendly way.
}]);
I am aware that $location isn't available in .config, so the above method won't completely work, but it's just food for thought.
I'm also open to any other suggestions on how to do all the configuration in AngularJS, because I haven't really found a good, clean way to specify app constants without having to use [insert build tool here] and create lots of constants and clutter my DI. I don't think AngularJS was intended to create such cluttered dependency management, but if I'm wrong, someone please correct me and explain a good way to set up better dependency management.

Categories

Resources