Should I use `this` or `$scope`?
AngularjsAngularjs Problem Overview
There are two patterns in use for accessing controller functions: this
and $scope
.
Which should I use and when? I understand this
is set to the controller and $scope
is an object in the scope chain for views. But with the new "Controller as Var" syntax, you can easily use either. So what I'm asking is what is best and what is the direction for the future?
Example:
-
Using
this
function UserCtrl() { this.bye = function() { alert('....'); }; }
<body ng-controller='UserCtrl as uCtrl'> <button ng-click='uCtrl.bye()'>bye</button>
-
Using
$scope
function UserCtrl($scope) { $scope.bye = function () { alert('....'); }; }
<body ng-controller='UserCtrl'> <button ng-click='bye()'>bye</button>
I personally find the this.name
to be easier on the eye and more natural compared to other Javascript OO patterns.
Advice please?
Angularjs Solutions
Solution 1 - Angularjs
Both have their uses. First, some history ...
$scope is the "classic" technique while "controller as" is much more recent (as of version 1.2.0 officially though it did appear in unstable pre-releases prior to this).
Both work perfectly well and the only wrong answer is to mix them in the same app without an explicit reason. Frankly, mixing them will work, but it will just add to the confusion. So pick one and roll with it. The most important thing is to be consistent.
Which one? That depends on you. There are many more examples out there of $scope, but "controller as" is picking up steam as well. Is one better than the other? That's debatable. So how do you choose?
Comfort
I prefer the "controller as" because I like hiding the $scope and exposing the members from the controller to the view via an intermediary object. By setting this.*, I can expose just what I want to expose from the controller to the view. You can do that with $scope too, I just prefer to use standard JavaScript for this. In fact, I code it like this:
var vm = this;
vm.title = 'some title';
vm.saveData = function(){ ... } ;
return vm;
This feels cleaner to me and makes it easy to see what is being exposed to the view. Notice I name the variable that I return "vm" , which stands for viewmodel. That's just my convention.
With $scope I can do the same things, so I'm not adding or detracting with the technique.
$scope.title = 'some title';
$scope.saveData = function() { ... };
So its up to you there.
Injection
With $scope I do need to inject $scope into the controller. I don't have to do this with controller as, unless I need it for some other reason (like $broadcast or watches, though I try to avoid watches in the controller).
UPDATE I wrote this post about the 2 choices: http://www.johnpapa.net/do-you-like-your-angular-controllers-with-or-without-sugar/
Solution 2 - Angularjs
$scope
is being removed in Angular 2.0. Thus, using this
would be an approach others want to follow as the date of release of Angular 2.0 comes closer.
Solution 3 - Angularjs
My opinion is that 'this' in javascript has enough issues on it's own, and that adding another meaning / use for it not a good idea.
I'd use $scope, for clarity's sake.
UPDATE
There is now the 'controller as' syntax, discussed here. I am not a fan, but now that it's a more 'official' AngularJS construct it deserves some attention.
Solution 4 - Angularjs
I think Controller As is better as it allows for more easily nesting scopes as described by Todd Motto here:
http://toddmotto.com/digging-into-angulars-controller-as-syntax/
Also, it will insure that you always have at least one . in your binding expression which forces you to follow the don't bind to primitives recomendation.
Plus you can decouple from the scope which is going away in 2.0.
Solution 5 - Angularjs
The Angular documentation explicitly tells you that using this
is recommended. That, in addition to the fact that $scope
is being removed is enough reason for me to never use $scope
.
Solution 6 - Angularjs
jason328's "$scope is being removed in Angular 2.0" sounds a good reason to me. And I found another reason to help me make the choice: this
is more readable -- when I see fooCtrl.bar
in HTML, I immediately know where to find the definition of bar
.
Updates: not long after switching to this
solution, I started to miss $scope
way that needs less typing
Solution 7 - Angularjs
##I prefer a combination.##
A simple console.log of $scope and 'this' after populating them with some mock data will show you that.
$scope allows access to under the covers parts of a controller, for example:
$$ChildScope: null;
$$childHead: null;
$$childTail: null;
$$listenerCount: Object;
$$listeners: Object;
$$nextSibling: Scope;
$$prevSibling: null;
$$watchers: null;
$$watcherCount: 0;
$id: 2;
$parent: Object;
foo: 'bar';
** Properties and methods with $$ are not recommended to mess around with by the Angular team, but the $ can be safe game for doing cool stuff with $parent and $id.
'this' gets straight to the point, attaching 2-way-bound data and functions. You'll only see what you attached:
foo: 'bar';
##So why do I prefer a combination?## In ui-router nested apps, I can access the main controller, set and call universal values and functions inside a child controller:
In the Main Controller:
// Main Controller
var mainCtrl = this;
mainCtrl.foo = 'Parent at the bar';
In the Child Controller:
// Child Controller
var mainCtrl = $scope.$parent.mainCtrl;
var childCtrl = this;
// update the parent from within the child
childCtrl.underageDrinking = function(){
mainCtrl.foo = 'Child at the bar';
}
// And then attach the child back to a property on the parent controller!
mainCtrl.currentCtrl = childCtrl;
Now, you can access parent from within child and child from the parent!
Solution 8 - Angularjs
Both work, but if you apply things that are appropriate for the scope to $scope, and if you apply things that are appropriate for the controller to the controller, your code will be easy to maintain. To the people who say "Ugh just use scope forget this Controller as syntax"...It may work the same but I wonder how you'll be able to maintain a huge application without losing track of things.