Angular.js: REQUEST FOR FEEDBACK: `angular.component()` - default directive controller name

Created on 2 Jan 2016  ·  59Comments  ·  Source: angular/angular.js

We should use a consistent default value for the name of a component's directive controller when it is attached to the scope. See https://github.com/angular/angular.js/issues/10007#issuecomment-166704255

Currently we are defaulting to the canonical name of the component. This is not ideal as

a) component names can become long and unwieldy for use in a template
b) it is more complicated to automatically update the template to be used in Angular 2, where the context is the controller.

The criteria for the name are:

1) it must be the same for all components
2) it must start with $
3) it must be short (2-4 chars)

In addition the name should represent what is actually being published to the scope.

Some of previous suggestions include:

  • vm - this is the commonly used name in many applications but the controller is not necessarily a "view model"
  • $comp - this is the current suggestion from the team but can be confused with compare and is not that short
  • $ctrl - this can be confused with input ConTRoL elements
  • $this - the controller is not really this in the template, since the context is still actually the scope
$compile feedback feature

Most helpful comment

So the votes are in and it looks like this:

$comp  4
$cmp   2
$ctrl  19
$vm    3
$this  3
$ctx   2
$vc    1

The clear favourite is $ctrl. As well as being popular it passes the criteria posted at the top of this issue. In addition it doesn't introduce any particularly new concept. The thing being referred to really is a controller (a component/directive controller) of which Angular developers already understand and just as some developers have gotten used to using vm in their directives it will not take long for developers to cotton on to this default.

All 59 comments

c) programmers are tempted to use isolate:false and access to ancestors controllers directly.

@drpicox - I am tempted to say that we ban isolate: false for components created using this helper.

I agree, after considering this:

  • isolate: true when restrict is 'E': for me they are truly components, in where $ctrl notation has full meaning
  • isolate: false when restrict is 'A': for me they are _decorators_, a kind of enhancer of the existing components, in this case $ctrl collides so the current nomenclature it's fine

But I consider that the second case is better to do with directives, _decorators_ are not frequent, usually low level, and not suited for juniors.

So probably is good idea to ban isolate: false.

In other track of thinking, about _decorators_, a function to get the controller of the 'E' component of the current entity should be good idea, specially to write generic _decorators_ to deal with any current component (require forces to know in advance which controller is and you cannot use a kind of interface of what are you looking for).

I like $cmp, but find $comp even better, because it's clearer.

I like $cmp, but find $comp even better, because it's clearer.

I like $comp. Whenever I see $cmp I think "compare".

different suggestion: why not have the name of the component as the controller instance name?
ex: user-profile -> scope.userProfile

@tabanliviu That's how it's currently done on master but @petebacondarwin mentioned in this very issue, in the first post, why a common name is better.

@mgol :+1: I think I glossed over that when I read the ticket. Should this change be considered more of a ngUpgrade issue? I think in the context of angular 1.x the current implementation is a good solution. Perhaps exposing this as a settings function that takes the component name and outputs the controller name? this way it serves the current pattern and a future migration path.

Bikeshed time.

+1 for $ctrl.

Ctrl has lots of pre-existing culture in Angular 1 documentation and examples as the "controller" suffix. Try googling "angular ctrl" for good measure.

The current choice of deriving it from component name is quite nasty, as they indeed tend to get pretty long in real applications.

:+1: for $ctrl, $vm as a default feels more like a statement of how controllers should be used.

+1 for $ctrl.

We debated this pretty heavily on the ng-forward team and decided that ctrl was a less loaded term than vm.

I vote for $ctrl and I'd be very happy if this encourages ppl to not call their controllers vm anymore :P

Oh, I'd also like to add that

this can be confused with input ConTRoL elements

Nah. Not really.

$ctrl

I think that would be most comprehensible and intuitive for everyone.

+1 $ctrl

Other suggestions:

  1. $as - like controller as
  2. $at - like @ - while in coffee script it references to 'this' context
  3. $class - although 5 chars, it's close to ng2 component class notation.
  4. $prox - since conceptually, the Ctrl instance is a proxy to a services layer
  5. $ctx - shortcut for context
    Thanks.

I vote for $this because in ng2 this of controller is context of template (and In my opinion component is very good in role of transition tool between ng1 and ng2).

+1 for $ctrl

I also prefer the $ctrl property, because it represent the component controller.

+1 for $ctrl

+1 for $this

I would even go with this and drop the $ if it wasn't too much of a hack to do it. It is also the only option which is not short for something else, and I hate abbreviations. :)

I would go for $ctrl or $cc (being short for component controller)

+1 for $ctrl

We could call it just $troll, it has a bit of $this and half of $controller. No, just kidding, I'm fine with $ctrl. :+1:

$ctrl + 1

$vm

Pros

  • less new concepts
  • short
  • doesn't represent what the object really is (but transitioning developers will get it...and that's the point)

Cons

  • doesn't represent what the object really is (but transitioning developers will get it...and that's the point)

$ctx - shorcut for context.

More general than $ctrl, less anonymous than $vm, no confusing like $comp or $this.

I gave a look at the template engines (Jade, Handlebars, Mustache.js, Dust.js, Nunjucks, EJS, etc.) and it seems the names context, locals or data are used for the variable name passed to the render method.

Also $ctx, for context, has not the same cognitive overload as $ctrl (or $this) and, indeed, you said in Angular 2, where the context is the controller.

@albertosantini - one problem with $ctx is that the actual context is the current scope, which is also accessible directly by this.

$vc - stands for View Controller.
i've found a reference in apple's docs

tldr;

"...The UIViewController class defines the methods and properties for managing your views, handling events ... "

I vote strongly for $this:

<textarea ng-change="$this.handleChange">

_Pros:_

  • BIGest advantage: You don't need to do any ctrl = this inside your Controller, to make both entities look the same.
  • Anything other than $this feels like Angular is introducing even _"more proprietary language"_, which is one of the popular complaints about Angular. Your Controller will become polluted like that:
  controller: function() {
    var ctrl = this;

    ctrl.items = [];
    ctrl.text = '';
    ctrl.handleSubmit = function () {
        ctrl.items.push({text: ctrl.text});
        ctrl.text = '';
    };
  }

instead of the cleaner, elegant, and framework-agnostic

  controller: function() {
    this.items = [];
    this.text = '';
    this.handleSubmit = function () {
       this.items.push({text: this.text});
       this.text = '';
    };
  • The latter is a pure JavaScript function that can be re-used anywhere with or without Angular. The former would look out of context anywhere else.
  • Note how even the syntax highlighter is your friend in the latter snippet and how it is fighting you back in the former. Code readability is an important issue.
  • This syntax is similar to React as appears on their landing page:
<textarea onChange={this.handleChange}>
  • In React both DOM context and Controller instance are treated as exactly the same entities, and React even capitalises on that, claiming their approach is simpler.
  • Angular is surely not React, but many people are using or looking at both, so more similarity would feel more friendly aka less confusing to them.

@dmitriz One problem with $this in AngularJS, is that in the template the context (i.e. this) really is not the controller. It seems that in React (and Angular 2) they really are the same thing and so it makes sense to use this (or $this). In Angular 1, they are not the same and so $this could actually cause even more confusion.

Regarding the JavaScript side of things, it is very common in ES5 code to alias this to something else because of the binding issues of this when calling free methods. So controllers will still often have something like var that = this anyway, in which case one may as well use var ctrl = this.

That being said there is no requirement to do this in your controllers if you don't want. It is perfectly reasonable IMO to use this internally in an object, but then refer to an object by some other name when using it from the outside.

@dmitriz, you don't have to have the same alias in the controller and in the view (I never do). Plus I always use var self = this in the controller, to avoid having to .bind(this) for callbacks etc.
So, this shouldn't be an issue, imo.

Regarding other options:

  • $ctx: I don't like this, because (as @petebacondarwin mentioned), the controller is not the context of the expressions.
  • $this: I don't like this, because (in Angular expressions) this is a special alias to the current scope, so having this --> scope and $this --> controller would be even more confusing. (I would have liked it otherwise.)
  • $vm: I don't like this (for reasons already mentioned), but I could go with it if nothing better meets our constraints.
  • $cmp: Not super-satisfactory (because not 100% accurate), but declarative enough. Could go with it if nothing better meets our constraints.
  • $comp: I prefer $cmp, because it's shorter (and I don't find it any more "confuse-able" with compare than $comp).
  • $ctrl: I pretty much like this. It's quite short, declarative and as accurate as it can get. I've always suffixed my controllers with ctrl and I've never witnessed any confusion with ConTRoL (but more knowledgeable people insist there's been confusion :)). If we decide confusion is not an issue, I'd definitely go with this, but I'm fine goind with something else.
  • $troll: Need to give it some more thought. It certainly has potential :stuck_out_tongue:
  • Other options ($as, $at, $cc, $prox, $vc): I think they are introducing new concepts and will be more confusing than helpful.

I'm voting for $ctrl, because it _is_ the directive controller. Simple.

Against the other ones:

  • $vm -- As already pointed out is not a required intention of usage => either confusion in pattern/code reading or less choice for the developer (forced to implement vm)
  • $cmp -- Well, it is not the component itself but (only) the controller? So actually misleading?
  • $this -- Also already mentioned, it is confusing. What does the controller instance make it "this" in the scope? Semantically, I don't see this could be.. well.. intelligible?
  • $ctx -- Actually the same as $this.

Also like Pascal already said: I don't see confusion with control elements. Unless Angular2 injects all DOM/input elements in such manner (i.e. $ctrl, $val, $cmbx, and so on), I don't see this being an issue.

+1 $ctrl

In the same line than previous comments:

  • $vm,$as,$at,$cc,$prox,$vc,$ctx,...: introduces new unnecessary concepts to programmers
  • $this: because this already exists, it may be confusing for programmers
  • $cmp or $comp: (better first) it should be nice because it focus programmers into the component model, but they may be not straight forward
  • $ctrl: is just what is being published in the scope, the controller, so it seems really clear easy to understand and to use

I see, thanks for clarifying, I didn't know this = $scope but, yes, that rules it out.

Then $ctrl sounds like the next best choice, apart from $troll that is :)

+1 for $ctrl: most intuitive and most generic

@petebacondarwin Thanks for the details.

So +1 for $ctrl.

I preffer the declarative $ctrl as the default name.

Why no good?

@petebacondarwin @PascalPrecht

Why isn't VM a good representation?

(If you already discussed it on a different issue, just link to it if you can)

Because AFAIK, controllers in Angular are closer to View Models rather than classical controllers from MVC. but maybe I'm missing something.

+1 for $vm

I agree with @QuinntyneBrown 's points -

it's shorter.

but more important -

@johnpapa 's style guide is very popular, and a lot of people I know refer to it as part of their "new developers" training program.

If we change this here, we should consider the effect it will have on new developers (maybe submit a PR to the style guide)

That's why I like the shorter "$vm" name (BTW, why must it start with $ ? :)

(BTW, why must it start with $ ? :)

Angular defined names start with $ when they share the name space with programmer definitions, it avoids collisions. In this case, it is defined by Angular and it is defined inside the scope, where the programmer can have its own definitions. Using $ we avoid name collision and Angular behaves consistently with what programmers expect.

(@johnpapa) The purpose of this style guide is to provide guidance on building Angular applications by showing the conventions I use and, more importantly, why I choose them.

Style Y032 Use a capture variable for this when using the controllerAs syntax. Choose a consistent variable name such as vm, which stands for ViewModel.

So it does not matter if it is vm, ctrl, or troll it just have to be a consistent variable.
In addition, as I pointed earlier, the idea is not to add new concepts: vm stands for ViewModel, if you are not using View Models or are not familiar with it, you will not understand what vm or ViewModel stands for, which will be confusing.

I am not a fan of confusing names. I think ctrl is confusing. It is controller? control (like html control)? and isnt this for a Component?

I vote for either vm or comp. vm is commonly used and easy to explain. comp is new, but not hard to divine.

How about $ctlr (i.e. ConTroLleR) rather than $ctrl?

+1 $comp

@petebacondarwin Oh the amount of dyslectics (like myself) who will bomb us with issues about this... :)

@drpicox Thanks for the explanation, I see your points and they are valid. it's a tough one, but I can share that at least from my experience, I had no trouble teaching developers the "vm" convention, and helped a few companies structure their massive app that way, they got it pretty fast, but maybe I'm alone in this experience.

But I understand your points. agree with $

I'm still for $vm though, but am fine with $comp as well...

@wesleycho from the Angular UI Bootstrap team seems to be strongly against vm:
https://github.com/angular/angular.js/issues/10007#issuecomment-166707284

+1 for $ctrl

@shairez I share completely your point about having a convention, I'm a Freelance Architect with tens of projects behind, the vm convention helped a lot, but I have still some issues. It turns out that there are people resisting to use it. Probably the resistance should be lower if this convention comes from Angular itself, but I am sure that if the name was $ctrl they would accept it as is, without any resistance. $ctrl is just straight forward.

So the votes are in and it looks like this:

$comp  4
$cmp   2
$ctrl  19
$vm    3
$this  3
$ctx   2
$vc    1

The clear favourite is $ctrl. As well as being popular it passes the criteria posted at the top of this issue. In addition it doesn't introduce any particularly new concept. The thing being referred to really is a controller (a component/directive controller) of which Angular developers already understand and just as some developers have gotten used to using vm in their directives it will not take long for developers to cotton on to this default.

Awesome, $ctrl it is!

Issue for 1.4 and lower - can't name an 'as name' with $ctrl

Another concern I'd like to raise is that in angular 1.4 and lower, we can't really use "as names" starting with a $ sign.

It gives the following error:
Error: [$controller:ctrlfmt] Badly formed controller string

Some companies have trouble upgrading to the latest versions, and it can take them a several months.

They still want to keep up with the conventions, so their upgrade process will be simpler in the future.

For them, switching from vm to $ctrl is impossible.

What do you think? any suggestions?

perhaps migrate in phases:
start with converting vm to ctrl
when 1.5 is release, "upgrade" ctrl to $ctrl

Another possible way - although verbose - is to generate controllerAs alias in runtime, checking angular.version. something like:

 angular
        .module('github')
        .directive('issueThread', issueThread);

    /* @ngInject */
    function issueThread () {
        // this can be required as a module if using some module loader
        // or - another way is using global on angular namespace (i know it a bad practice - hwoever just to indicate reuse of this check 
        let prefix = angular.version.minor === 5 ? '$' : '';
        let controllerAs = prefix + 'ctrl';
        // with template strings
        var controllerAs = `${prefix}ctrl`;

        var directive = {
            controller: controller,
            restrict: 'E'
        };
        return directive;

        function controller() {
        }
    }

@orizens What about templates?

@shairez Uhmmm it makes sense, $ symbols are intended only for angular internals... may be having some kind of forward compatibility in the next minor is nice.

@drpicox you got a point there :).
Again, one solution i can think of (hacky one...), is, "replace" ctrl with $ctrl in template in runtime / build. That can be achieved easily if the project is built with es6 and modules. otherwise, it's a task for gulp/grunt/npm at build time.

Why not just use controllerAs ?
It's not an ideal solution (and indeed we might need to revise the RegExp that extracts the identifier from the controller string (if any), but using controllerAs is both backwards and forwards compatible :)

(If anyone wants to have a shot at updating that indentifier extracting RegExp, it's right there btw.)

@gkalpak that's a good point, moving forward promoting the use of the controllerAs property is good as more and more people will also transition to using components in their 1.4 and lower versions I believe.

But, I think it might be confusing if we'll start teaching people about $ctrl and in some cases it works and in some it isn't.

So a forward compatibility (not sure how), is a great idea!

@shairez did you (can you) create a new issue to track this?

I created #13736 which allows $ in identifier, when using <ctrl> as <identifier>.
Still the allowed identifiers are different between controller: '... as ...' vs controllerAs: '...'.

That said, I am not sure that promoting controller: '... as $ctrl' is a good way of keeping up with conventions. It is much more difficult to upgrade controller: '... as $ctrl' than controller: '...', controllerAs: '$ctrl'.

Thanks @gkalpak - I agree that we should probably encourage use of the controllerAs property rather than the controller as syntax.

One thing is: documentation of component says: "Component definitions are very simple and do not require much of the complexity behind defining general directives".
Another one: controller in directive is only necessary if you build complex directives talking to each other. Otherwise a link function is more than enough (e.g. "use controller when you want to expose an API to other directives. Otherwise use link" in Developer Guide directive, and from my experience directives implementing same functionality with link instead of controllers used some hundred times in ng-repeat are much quicker.
So...
I don't find in Component ("simple" directive) the way to do "simple" (link function), only the heavy one (controller).
Do I miss something?
Thanks for the explanation.

@frfancha - the performance improvement is due to not having to use the $injector to instantiate the controller, right? Perhaps you have some performance measurements you can provide?

The idea of the component helper is to make it simpler (in LOC sense) to write component type (isolate, element) directives; and easier to write code that is more inline with how things are done in Angular 2.

If there is a performance issue in a specific app then it would be fairly straightforward to convert a component directive over to use the more general directive helper.

I think we need to take a look at the other API docs and developer guides to ensure they are consistent with the new component() helper.

@petebacondarwin At the beginning we wrote all our directives with controller, just because it was shown this way in the first tutorial we followed.
Only after we found it took about 15 seconds to "open" a certain page with 1000 directives (5 by "rows" in ng-repeat x 200), we read more about directives and understood that controllers are useless if you don't "speak" between directives (by requiring the controller of another one). After "rewriting" all with link functions instead of controllers (rewrite is a big word as it was just copy/paste of the code in link instead of controller), time to display the page was 8 seconds.
Note that these are firefox measures, at that time we didn't use Chrome. Now we use it and I estimate the time in Chrome to be the third of Firefox (and memory usage the fourth (and without memory leak, which is great, in Firefox our application is known to be "slow in the afternoon)).
We are generally very happy with angular (we have converted all our data-entry applications from Smalltalk windows application to WEB API + angular (in case that would interest you to see it?? I'm sometimes in London).
But I'm surprised by the choice of controller to support the "simple way" to do directive

thanks @gkalpak !

@petebacondarwin a separate issue isn't relevant anymore right? (Because of the PR)

I agree (as I wrote), we should educate people to use the controllerAs property, but just mentioned it because I predict people will run into it.

Was this page helpful?
0 / 5 - 0 ratings