The Angular.js team have added a new way to access variables within your controller. When I first saw this I glossed over it and missed the point thinking it was just shortcut syntax, more ways of doing the same thing, but its not. In this post I’ll explain why the controller as syntax is good and you should be using it.

The angular controller as syntax looks like this.. ng-controller=“MyController as ctrl1” with access like this.. ng-click=“ctrl1.doit();”. This is an extension to the original way of ng-controller=“MyController” with ng-click=“doit()”.

Whats good about the as syntax is you can reference variables directly without getting lost by any of the child scopes.
eg,

 <div ng-controller=“MyController as ctrl1">  
<h1>button number {{clicked}} was clicked</h1>
<div ng-if=“true”>
<button ng-click=“clicked=1”>1</button>
<button ng-click=“ctrl1.clicked=2”>2</button>
</div>
</div>

The trap here is that ng-if creates a child scope from the scope of MyController. So the assignment in the template by ng-click can assign to the child scope instead of the one you actually want. ctrl1.clicked is always to the right one, it doesn’t matter how many ng-ifs you put around it. You can work around this without the as syntax by using $parent and the “dot rule”, but thats error prone. On a side note you should favour ng-show over ng-if, it doesn’t have this problem and is usually enough.

Access from the controller is a little bit different too. You now access the variables through the controllers `this` reference rather then the scope directly. The advantage here is that your not using the scope with its complexity of its hierarchy.
 controller('OneCtrl', function(){  
this.doit = function(){...};
});

If you really need the $scope you can still have it, just inject it like normal. But there maybe better solutions without it. If you were using the scope hierarchy to communicate between controllers consider event broadcasting, like $rootScope.$broadcast, this is more explicit, easier to test and less error prone. If you needed $scope.$apply, you must be doing something weird outside of the angular lifecycle, try moving that into a service or a directive.

The angular as syntax can also help with code reuse. Imagine a image gallery controller it’ll have some <img> tags in the template which won’t be shareable but shared logic will be in the controller. You may even want to use different templates in the different places its used. By accessing the controller with the as syntax its safe and simple to use along side other model controllers.
A common gallery could be done with a directive, but if your not actually need access to the DOM, a utility controller would be the simpler way to go.

Unit testing has some slight changes too, you save a reference to the controller instance and access your variables through that.

 describe('testing controllers with angular as syntax', function(){  
angular.module('module', []).
controller('OneCtrl', function(){
this.name = 'One';
});

beforeEach(module('module'));

it('initializes and can get the value', inject(function($controller){

var ctrl = $controller('OneCtrl', {});

expect(ctrl.name).toBe('One');
}));
});


Consider how the As syntax has been made. Its really simple, it just assigns the controller to a value in the scope. Understanding this and be confident that angular.js Isn't magic and that this can work happily along side other code.

Be careful with the `this` reference. Remember in javascript the `this` reference changes. Look out for traps like this.
 controller('SomeCtrl', function(){  
var self = this;
this.name = 'One';
this.obj = {
name: 'two',
returnName: function(){
return this.name; // returns 'two' not 'One'
}
};


So thats how to write more maintainable code using the angular js controller as syntax. If you think I’ve left anything out let me know.


Code long and prosper.


Related Posts