3

Cannot Use ControllerAs this

Can anyone explain the following scenario to me, please?

Works

ng-controller="Parent as thus"

Breaks

ng-controller="Parent as this"

That single letter which makes it a keyword -- which I want -- wrecks the forest.

Why is this?

P.S. I'm aware of the vm convention, but I find it disturbs portability of controllers/viewmodels.

3
  • 3
    but I find it disturbs portability of controllers/viewmodels ? can you please explain "this"? no pun intended Commented Jul 11, 2016 at 20:23
  • 2
    I'm guessing Angular tries to evaluate that passed in string, and this is a reserved word. Commented Jul 11, 2016 at 20:23
  • In terms of architecture, its a bad practice to couple to your base-lib/framework. As so, you may want to port your generic Viewmodel from system to system. I find the vm approach to incur some degree of change-cost when ports occur. For instance, if I took a generic CalendarViewmodel that is used for all projects, I would have to go through all references of this and turn it into vm; just for that controller. That's the oversimplified example, and its just one of many. A lot more to be said here. Commented Jul 11, 2016 at 20:32

2 Answers 2

6

The problem is certainly not that this is a reserved word in JavaScript. There is no rule in the controller as syntax that says you would need to assign the value of this to a variable with the same name as the controller and I'm pertty sure angular won't do such thing either. Why would it? That would be incredibly stupid use of Function constructor and just a needless bug.

There's a simple way to test that JavaScript reserved words are not the issue here. Name your controller "throw". "Parent as throw". throw is a reserved word, but does that throw errors? No. Does that work? Yes.

this is, however, reserved in the context of angular's own template expressions. It's used to refer to the current scope of the expression.

<div ng-controller="Parent as this">
    {{log(this)}}
</div>


angular.module('testApp', []).controller('Parent', function($scope){
    this.test = 'foo';
    $scope.log = function(arg){
        console.log(arg);
    };
});

The above won't throw errors, but it won't log the controller either. Instead, it will log a scope object containing the log function and $parent and what not.

In fact, it will also contain something intresting to us: property this: Object, our controller.

And sure enough, change the template expression to {{log(this.this)}} and it will log the controller instance just fine. Still wouldn't use 'this' as the name though, it would probably just cause more bugs by mistake than undefined functions ever have.

Sign up to request clarification or add additional context in comments.

7 Comments

While this is certainly MORE informative, it still doesn't give a definitive answer as to why AngularJS is refusing to parse the keyword.
@DavidL What makes you think angular doesn't parse it? In the example above, angular certainly parses the "Parent as this" expression. It just refuses to override the value of word this in the template scope. There could be many reasons for that, from design decisions to implementation details. Or are you experiencing actual errors that I just don't know about?
"this is, however, reserved in the context of angular's own template expressions". What I'm saying is that this claim would be ideally backed up with the source that demonstrates this. The filter is obviously applied somewhere in the expression syntax and the source for it would be wonderful. Your explanation otherwise is perfectly sound.
@DavidL, its because Angular does reserve this as a keyword in order to track scopes. As scopes are chained using Prototypical Inheritance, parsing this will resolve to the first given object on that chain which contains a property. Its a difference between Scope & Instance. It does parse the keyword, but it resolves to the immediate scope, the root-scope, or anything between.
@noppa, I think you're referring to my last sentence there, but that's just wishful thinking. I think they're doing it the best way, actually, in order to encapsulate what varies. I think you still need to have the scope/prototype chain, which probably necessitates having this as the markup's context. I think we totally agree ;)
|
0

You are cannot use this as the instance name. this is a reserved keyword.

It would be the equivalent of doing:

var this = new Controller();

You can see that is wrong. It should be something like:

var ctrl = new Controller();

This is essentially what angularJs does behind the scenes when you do controllerAs="Controller as ctrl"

2 Comments

Well, I would think what Angular is doing is more like var hash = {}; hash['this'] = new Controller(); -- which is totally legal syntax. You can indeed have an instance variable referenced as this.this.
Controller as ctrl has internally defined $scope.ctrl = this; in the controller's body.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.