254

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:

  1. Using this

    function UserCtrl() {
      this.bye = function() { alert('....'); };
    }
    
    <body ng-controller='UserCtrl as uCtrl'>
      <button ng-click='uCtrl.bye()'>bye</button>
    
  2. 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?

Michael
  • 8,362
  • 6
  • 61
  • 88
SenseDeep
  • 3,026
  • 3
  • 17
  • 19
  • Is the "UserCtrl as uCtrl" syntax new? I don't see it documented on the 1.0.6 or 1.1.4 ngController pages. – Mark Rajcok May 18 '13 at 02:52
  • Okay, it is documented on the [new 1.1.5 ngController page](http://code.angularjs.org/1.1.5/docs/api/ng.directive:ngController). – Mark Rajcok May 24 '13 at 23:53
  • 1
    Best Explanations for $scope and this http://codetunnel.io/angularjs-controller-as-or-scope/ – Sai Sep 22 '15 at 07:29
  • Using 'this' seems to be new as of Google I/O 2013 http://m.youtube.com/watch?v=HCR7i5F5L8c Also, check this answer: https://stackoverflow.com/questions/11605917/this-vs-scope-in-angularjs-controllers – AlanW May 18 '13 at 01:06

8 Answers8

231

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/

John Papa
  • 21,880
  • 4
  • 61
  • 60
  • 4
    Personally I also follow your approach using vm. The only code smell I've picked up is when you need to specifically interact with $scope, e.g. subscribing or broadcasting events, accessing form validation variables inside your controller etc. This leads to a somewhat mixed environment where you still need to inject $scope even though you use the controller as feature. – Beyers Nov 17 '13 at 14:10
  • 10
    Right. $scope is still used for in that case, but it is used more as a service. When we inject angular services ($scope, $q, etc) they provide some feature we need. $scope allows us to watch, apply, uses messages as well as data binding. And even when using controller as, $scope is still used, its just abstracted – John Papa Nov 17 '13 at 14:19
  • Thanks John, that's what my conclusion was as well. – Beyers Nov 17 '13 at 14:24
  • I think using $scope in Directives and having inheritance automatically in DOM-Tree are important points about $scope. Having that kind of inheritance is a good idea, I don't know. It is like a global object and can causes unexpected bugs. $scope should be better documented. – Tolga Nov 17 '13 at 16:42
  • 1
    `var vm = this;` do you need to call it 'vm' in the view, too? 'controller as vm'. Do they have to be the same? – Javid Jan 13 '14 at 09:51
  • @Javid the `vm` in the controller and view do not have to be the same name. i just do that by convention because it is easier to be consistent, it is short to type, and vm conveys that it is the View's Model (aka ViewModel). You can of course deviate from this if something else interests you. – John Papa Jan 13 '14 at 16:54
  • Thank you @John. I watch your courses on [Pluralsight](http://pluralsight.com/). I learn alot from you. – Javid Jan 14 '14 at 22:17
  • 2
    @JohnPapa - Why don't the SideWaffle templates "return vm;" when using Controller As? – Kevin Feb 10 '14 at 06:19
  • 2
    @Kevin Controllers effectively act as a Ctor and thus return "this" already. – John Papa Feb 15 '14 at 13:45
  • @JohnPapa I see this answer is dated back 2013. I am on the stage of finalizing my new app where I never once used `controllerAs`. I have used $scope through the app and never did I have an issue with overlapping scope. Now that I see more and more people using (or suggesting) `this` over `scope`, I am in a dilemma if I should spend my time rewriting everything from `$scope` to `this` which brought me to your answer here. So, as of today considering the Angular future, would you still suggest `So pick one and roll with it. The most important thing is to be consistent.`? – Neel Nov 21 '15 at 17:34
  • If your app works I would be highly cautious on rewriting anything in it. It works, after all. So the risk in changing code in a production app has to be outweighed by the reward. ControllerAs will help you be in a better place to mentally prepare for Angular 2, but you would still need to change code to get there or use ngUpgrade. So no ... given what you have said, I would not change an existing working app. However, you could slowly start to do this as you make changes to your app, 1 V+C at a time. – John Papa Nov 24 '15 at 13:40
  • @JohnPapa as jason328 stated "$scope is being removed in Angular 2.0". If it is true, then what I should instead of $scope in my controller which uses $broadcast and $on. – Pradeep Dec 01 '15 at 12:32
  • there are EventEmitter constructs you can use in ng2 – John Papa Dec 03 '15 at 11:38
  • @JohnPapa Why is it called vm? We also define the controller functions so it's not only the data model. I'm confused. – Marc Apr 18 '16 at 20:03
  • vm == ViewModel == View's Model – John Papa May 02 '16 at 01:37
  • I'm having trouble with a similar implementation of your answer, please see http://stackoverflow.com/questions/38315538 – Cody Jul 11 '16 at 20:45
  • Quote "controller and view do not have to be the same name. i just do that". So you write `ng-controller="controller as vm"`, as also used in your awesome code style guide (https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md). Why? If you name all your controllers `vm` in the view, you might as well not use the controllerAs-Syntax at all – phil294 Nov 06 '16 at 01:47
  • Just thought I'd mention that when using bootstrap tabs, you start to see a reason for using var vm = this over $scope. Tabs have their own scope and so you can't use $scope as you'd think you could but you can use vm everywhere. So it has real functional reasons over just convention I think. – user441521 Feb 15 '18 at 19:37
69

$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.

thank_you
  • 11,001
  • 19
  • 101
  • 185
40

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.

Roy Truelove
  • 22,016
  • 18
  • 111
  • 153
  • 10
    I think we first need to understand the new "UserCtrl as uCtrl" syntax before we can say which we think is better. – Mark Rajcok May 18 '13 at 04:16
  • Re 'UserCtrl as uCtrl', I agree, this needs to be understood. I think it's a bad idea, for most of the same reasons as the arguments made here : https://groups.google.com/forum/#!topic/angular/84selECbp1I – Roy Truelove Nov 18 '13 at 13:43
  • 4
    If you are familiar with [oop in JS](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript) it makes perfect sense. A controller is a class, and angular uses the new operator each time a controller is created. You are welcome to dislike it, but stating there are issues with using 'this' is misleading. It is an acceptable use case for 'this'. – Michael Allan Jackson Apr 23 '15 at 17:07
  • $scope adds nothing to the clarity. In fact it can be be very difficult to know what is going on in the view when using $scope and you have nested scopes. The controller as syntax along with using this adds much more clarity. In the view it is nice and clear which controller's scope a method or property originates from. – ddelrio1986 Dec 27 '15 at 21:56
  • I'm having trouble with a similar implementation of your answer, please see http://stackoverflow.com/questions/38315538 – Cody Jul 11 '16 at 20:45
  • 1
    I agree with @ddelrio1986. Just had an issue with bootstrap tabs and agular with using var vm = $scope. Tabs have their own scope and so you aren't able to use this as you'd expect but with var vm = this, things just work as expected. – user441521 Feb 15 '18 at 19:39
11

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.

Ryan Vice
  • 2,133
  • 3
  • 23
  • 33
7

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.

tjespe
  • 704
  • 7
  • 17
4

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

ZZY
  • 3,689
  • 19
  • 22
3

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!

curtybear
  • 1,458
  • 2
  • 20
  • 39
1

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.

Nick Manning
  • 2,828
  • 1
  • 29
  • 50