Do You Like Your Angular Controllers with or without Sugar? | John Papa

John Papa

Evangelist on the loose

Do You Like Your Angular Controllers with or without Sugar?

...

sugar-make-us-age-1Even if you’ve only read about Angular, the odds are you’ve seen the rampant use of $scope in the C of MVC (controllers). $scope is the glue between the Controller and the View that helps with all of our data binding needs. Recently the Angular team opened up a new way to use $scope with Controllers. So now you can use $scope (what I’ll refer to as Classic Controllers) and you can use this (what the Angular team and I refer to as Controller As).
I hear a lot of questions about these 2 techniques. Everyone loves choice, but at the same time, most folks like to know clearly what they are getting or giving up with the choices. So let’s discuss the two controller constructs in Angular (with $scope and Controller As) and how scope plays in both of these.

Both Classic Controller and Controller As have $scope.

That’s super important to understand. You are not giving up any goodness with either approach. Really. 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 id appear in unstable pre-releases prior to this).

Both work perfectly well and the best guidance I can give is to try to be consistent with choosing one or the other. You can mix them in the same app, but for Pete’s sake have an explicit reason for it first. 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. Overall, for me it really just comes down to personal preference and mine is that I prefer the Controller As technique. 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).

This is another reason I prefer Controller As: I like knowing that I only inject $scope explicitly if I need something besides data binding. Listening for a broadcast message is one example. A watch is yet another, though I try to avoid watches in controllers.

Trends

There appears to, at this time, be more code examples out there using the classic approach with $scope explicitly. However I am seeing more and more examples of Controller As.

If you want a file template for creating controllers you can use SideWaffle, a plug-in for Visual Studio. It offers both flavors of controllers in its file templates. Don’t like sugar? choose classic controllers with $scope. Want some sugar? Choose controller as.

The Angular team has given us options and I’m glad they have. I personally prefer the Controller As technique. Either way you get data binding. With Controller As you get some sugar on top that makes working with $scope feel better, in my opinion. So you just have to choose if you want your Angular with or without sugar :)

tags: angular patterns
  • Joe Beernink

    I just picked up Angular (watched a lot of Pluralsight over the weekend, thank you very much). With no historical context, I greatly prefer the Controller As syntax. While I’m $scope works, the Controller As seems much clearer to me.

    On the flip side of things, I hadn’t worked in ASP.NET MVC since MVC3, and the whole idea that the client side now has a controller (which is actually a view model), blew me away, and seems to be a bit of a misnomer. It didn’t take too long to get used to the new terminology, but it was a bit of a shock to my outdated neurons.

  • Jesse Liberty

    John,

    You are not only a font, you provide a critical service to the community. Great article, thanks!

    -jesse

  • Daniel Root

    One possible +1 for the “Controller As” method is that done a certain way it can be made to port to other frameworks. I recently did a grid that worked both on Angular and on Knockout. On Angular, I just bound to the viewmodel. On Knockout I had to use KO mapping first to wrap the model, and provide a shim for $http. NBD if you’ve chosen a framework, but if you’re writing something to plug into other frameworks, it can be a bonus.

  • Sk.Tajbir

    very helpful. Thanks for sharing.

  • Malik Berger

    watching your plural sight video now. This posts helps clarify the $scope since you aren’t using it in your video. Thanks for all the hard work!!!

  • http://www.greglockwood.com/ Greg Lockwood

    Why do you avoid watches in your controllers? Isn’t that one of the primary ways you observe changes to properties? In particular, I find using watches to synchronise, say, a DB representation of an object and an in-page representation of the data, very helpful.

    We have even been able to use watches as a way of simulating Knockout’s “computedObservable()”, by dynamically registering watches on dependencies and re-running the function to generate the computed property if any of them change. What is your substitute for this kind of task?

    • johnpapa7

      Greg – I generally can find alternatives to putting watches in my controllers. For example, most things I want to watch are already data-bound in my view. So if an array changes that is bound to an ng-repeat, instead of a watch I just run my code wherever the array changes in the controller.

      For computed/calculated properties I often use ES5 object.defineProperty (getter/setter).

      I prefer to keep watches out if I have alternatives means. This also usually means I can eliminate the need for an “apply” in my test too.

  • Martijn Boland

    I’m missing one of the big pro’s of $scope: you can simply use it in async event handlers. With ‘this’, you always have to introduce extra variables (var self = this) to be sure you’re using the same ‘this’.

  • Joshua Bowdoin

    I notice that you do:

    vm.myFunction = myFunction;

    function myFunction(){
    //code here
    }

    Is this just style? or are there benefits to your approach versus just doing:

    vm.myFunction = function (){
    //code here
    }

    • johnpapa7

      Joshua – it is purely style on my part. I prefer to separate the function definition from where I expose it so I can easily see all exposed functions at the top. If my function is a 1 liner, I often leave it up top tho. If its not, then I separate it. Otherwise, I feel the code is harder to read when i am trying to find what features are exposed on the scope.

      • Joshua Bowdoin

        Thanks!

  • David Chase

    I personally prefer “controller as” syntax because when i have nested controllers I like to see what belongs to each controller..

    Thanks for the great article

  • http://vkelman-blog.blogspot.com/ vkelman

    There was an interesting discussion on $scope vs controller as here:
    https://groups.google.com/forum/m/#!topic/angular/84selECbp1I

  • James

    John,

    I’m just getting started with Angular and am using the SideWaffle templates as I build out the application. Because I’m a noob (both in Angular and Javascript) some things are entirely clear and I was wondering if there was a “best practices” site or somewhere I could learn where to store intermediate variables that I didn’t want to expose to users of the controller, but wanted to be initialized with it (and not in each call). For instance, I’ve got a search service defined (using the amazing Algolia) and as the service template also follows the “expose what you intend, hide everything else” pattern I wasn’t sure where to store the client variable the service uses to communicate with its server. Do I just declare them in the service/controller function scope or is there a better method?

    Thanks so much!

    James

    My Service (such as it is):

    (function () {

    ‘use strict’;

    // Factory name is handy for logging

    var serviceId = ‘algolia’;

    // Define the factory on the module.

    // Inject the dependencies.

    // Point to the factory definition function.

    angular.module(‘searchApp’).factory(serviceId, [algoliaService]);

    function algoliaService() {

    // Define the functions and properties to reveal.

    var service = {

    search: search

    };

    var algolia = new AlgoliaSearch(“myappkey”, “myapikey”);
    var index = algolia.initIndex(‘gear’);

    return service;

    function search(query, callback) {

    index.search(query, callback);

    }

    //#region Internal Methods

    //#endregion

    }

    })();

    • johnpapa7

      Variables declared in the service won’t be exposed unless you return them as part of the returned object. Or you can make your key a constant with angular. Or you can expose a series of constants from a confit service,which is what I often do. See my code from my course on that.

      Hope this helps

  • pupuzuken

    If I’m using some open source controllers I have found for certain functions, can these be integrated easily into Hot Towel? Or will I need to edit them to use vm instead of $scope?

  • David Land

    You’re missing the main feature of “controller as” which is to allow you to easily nest controllers and cleanly refer to the proper one inside your html.

    http://toddmotto.com/digging-into-angulars-controller-as-syntax

    {{ main.title }}

    {{ another.title }}

    {{ yet.title }}

%d bloggers like this: