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.
Related
I recently started to work with AngularJS and got the hang of the basics for it, but in the examples I've seen around, I came to find two different approaches in them.
Making the variables and functions private:
function myController(){
var controller = this;
controller.myVar = 0;
controller.myFunction = function(){...};
}
And making them public through the $scope:
function myController(){
$scope.myVar = myVar;
$scope.myFunction = function(){...}
}
I can understand the need to make something private, but to expose variables and functions as public doesn't add up to me since it feel like the Single Responsability Principle is broken in those instances.
Is there a good reason to make something public like that? Are there alternatives to making something public? Or am I worrying too much?
$scope is the older way of doing things in Angular. The new way is to use the controllerAs syntax -- which is when you bind the value of this to a variable.
They both work, but the newer controllerAs way of doing things was introduced for a number of reasons -- chief of which being because it was closer to what they were expecting the Angular 2 way of being. Further, the controller as way of doing things, allows people to have nested code scope in a view and have a better understanding of where the interpolated values are coming from. For example:
<div ng-controller="controller1">
{{someVal}}
<div ng-controller="controller2">{{anotherVal}}</div>
</div>
Since scope is inherited in Angular, it is difficult to tell whether the value for anotherVal is coming from controller1 or controller2. When using the controllerAs syntax, it clears that up a bit by being able to do something like this:
<div ng-controller="controller1 as ctrl1">
{{ctrl1.someVal}}
<div ng-controller="controller2 as ctrl2">
{{ctrl2.anotherVal}}
</div>
</div>
Now, it becomes obvious where those values are coming from.
However, to answer your question directly, you may still need to use the $scope object when you hope to access certain angular lifecycle hooks such as $scope.$watch, $scope.apply, etc.
I believe the main reason to make things public like that is for the purposes of testing and to let Angular "know" about certain data changes so it can have any "listening" views react and update to such changes.
You use $scope only when you do data-bindings or when you want to pass data between controllers, otherwise you don't have to do that.
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.
I would like to know what is the main difference between "Controller as" or "$scope" syntax in angularjs.
Do they have any performance impact,if yes which syntax is preferable.
"Controller as" syntax surely improve the readability of the code,as Knockout.js and other JavaScript framework follows the same syntax.
$scope will provide scope inheritance which sometimes give us weird behavior like
<div ng-controller="firstController">
ParentController: <input type="text" ng-model="parent"/>
<div ng-controller="secondController">
ChildController: <input type="text" ng-model="parent" />
</div>
</div>
app.controller('ParentController', function ($scope) {
$scope.parent = "parentScope";
}).controller('ChildController', function ($scope) { /*empty*/ });
a) Initially child will get the parent property and it displays 'parentScope' when we update parent child will also get updated. But if we have changed the child property now updating the parent doesn't modify child as it has got its own scope property.
b) If i am using controller as syntax changing child also updates the parent.
I've written a few answers to this question in the past, and they all essentially boil down to the same thing. In Angular, you are using $scope, even when you aren't expressly referencing it.
The ControllerAs syntax allows Angular to help you to write more efficient, fault tolerant controllers. Behind the scenes, when you use ng-controller="theController as ctrl", Angular creates theController as a property on $scope and assigns it as ctrl. You now have an object property you are referencing from scope, and are automatically protected from prototype inheritance issues.
From a performance perspective, since you are still using $scope, there should be little to no performance difference. However, since your controller is now not assigning variables directly to $scope on it's own, it does not need to have $scope injected. Also, the controller can much more easily be tested in isolation, since it is now just a plain JavaScript function.
From a forward thinking perspective, it's well known by now that Angular 2.0 will not have $scope, but instead will use features of ECMAScript 6. In any previews released by the Angular team showing migrations, they first begin by refactoring the controller to eliminate $scope. If your code is designed without the use of $scope based controllers, your first step in a migration is already complete.
From the designer's perspective, the ControllerAs syntax makes it much clearer where objects are being manipulated. Having customerCtrl.Address and storeCtrl.Address makes it much easier to identify that you have an address assigned by multiple different controllers for different purposes than if both used $scope.Address. Having two different HTML elements on a page which both are bound to {{Address}} and knowing which one is which only by the controller the element is contained in is a major pain to troubleshoot.
Ultimately, unless you are trying to spin up a 10 minute demo, you really should be using ControllerAs for any serious Angular work.
I would definitely recommend Controller As syntax.
It's cleaner, more efficient, you can organise your code much more and it's the new way of doing AngularJS.
Unless you're working with a team used to the $scope syntax, definitely use Controller As.
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.
I am confused on a couple of things with Globals in Angular. Below is my pseudo code.
1) With the way I have my GlobalCtrl placed, I am able to reference my $scope.modalOptions from all of my controllers. That being the case, I'm confused as to why I see people adding global properties to $rootScope instead of just adding them like I am doing here. Is that just in case they want to inject it into a service or something?
2) Should I be using a service instead of adding properties and methods to my GlobalCtrl? If so, why?
<div ng-app="app" ng-controller="GlobalCtrl">
<div ng-view></div>
</div>
function GlobalCtrl($scope, $location) {
$scope.modalOptions = {
backdropFade: true,
dialogFade: true
};
}
The 'Main Controller' approach is definitely preferable to using $rootScope.
Scope inheritance is there, so why not leverage it. In my opinion, that solution works well for most cases, i.e. unless you need to have a parallel controller somewhere (that wouldn't be a child of Main). In that case, the best way to go is to use a service and inject it where needed. Services (or rather factories, because that's what you'll probably be using -- read more about them here) are singletons and work well for sharing data across controllers.
Important to know about scopes
Scope inheritance is pretty much regular JavaScript inheritance at play. You should tend to use objects for your data, because they are passed by reference.
If you have a primitive like $scope.myString = 'is of a primitive data type'; in your parent controller and try to overwrite the value in a child controller, the result won't be what you'd expect -- it will create a new string on the child controller instead of writing to the parent.
Suggested reading here
Final thoughts
If you are using the nested controllers approach, do not forget to still inject $scope (and other dependencies) in the child controller. It might work without, but it's slower and hard to test, and last but not least -- the wrong way to do it.
Finally, if you have a lot of state variables to keep track of and/or a lot of usage points, it's definitely a good idea to extract them into a service.
Generally speaking global variables are considered bad practice, as they don't encourage encapsulation, make debugging difficult, and promote bloated code. Here's a good discussion of global variables: http://c2.com/cgi/wiki?GlobalVariablesAreBad.
A good rule of thumb is to add properties and methods to the most local scope possible and use services to share data between modules.