Angular.js

AngularJS Tutorial: AngularJS Controller As Syntax

In the previous installment of this series we discussed scopes and what problems nested scopes can cause. There are a couple of solutions to this problem: the so-called Controller As syntax introduced by AngularJS 1.2 and .component()  method introduced by AngularJS 1.5. The latter option is a recommended way to go if you are thinking about upgrading your application to newer Angular versions. In this post we’ll talk about AngularJS Controller As syntax.

As was mentioned previously, when we instruct Angular to use a controller with the ng-controller  directive, a new instance of a controller and a child scope is created. Alternatively, the same directive but with a different syntax can be used to create a controller and to attached it to a newly-created scope as the snippet below shows.

<section ng-controller="HelloController as vm">
    <h4>AngularJS Greeting</h4>
    <label for="name">Type your name here:</label>
    <input id=name type="text" ng-model="vm.myModel">
    <p>Hello {{vm.myModel}}!</p>
</section>

The differences are that, first, in the ng-controller directive we not only pass the name of the registered controller, but also, a variable name for an instance of the controller; vm stands for ViewModel but a more meaningful name can be used and we’ll talk about it later. Second, when we use double curly braces or the ng-model directive, we use vm.myModel to access to the variable defined in the controller. The following snippet shows how a controller using Controller As syntax looks like.

(function () {

  angular.module('app')
    .controller('HelloController', HelloController);

  function HelloController() {
    var vm = this;

    vm.myModel = 'World';
  }

})();

It differs from the version using $scope; we don’t pass the $scope variable to our controller, so there is also no necessity to add code that copes with minification. Also, we create the vm variable and store the value of this it it to prevent future problems when working with this. The most important point here that all the variables and methods are created inside the vm object; this helps to clear scope from our data and methods. The visualization of AngularJS scopes obtained by Batarang is shown in the following picture.

 

The fact that we don’t pass $scope to our controller doesn’t mean that it is impossible. In fact, $scope has useful methods and if we decide to use them we can pass $scope to our controller. The idea is to store everything we create in a special vm  object. To stress once again how Controller As syntax is used by AngularJS I’ll show you an example of a controller’s test that relies on it.

describe('HelloController scope tests', function () {
    var scope;

    beforeEach(function () {
        module('app');

        inject(function ($rootScope, $controller) {
            scope = $rootScope.$new();
            $controller('HelloController as vm', { $scope: scope });
        });

    });

    it('should be World', function () {
        expect(scope.vm.myModel).toEqual('World');
    });
});

Now we create a new $scope using $rootScope in order to rely on JavaScript prototypal inheritance and use scope methods. Also, we obtain the aforementioned root scope inside
beforeEach method and use Controller As syntax to obtain an instance of our HelloController from the $controller() function. Finally, inside the it() method, we obtain our data using scope.

A more succinct version of the controller’s test that doesn’t rely on AngularJS scope is shown below.

describe('HelloController tests', function () {
    var HelloController;

    beforeEach(function () {
        module('app');

        inject(function ($controller) {
            HelloController = $controller('HelloController');
        });

    });

    it('should be World', function () {
        expect(HelloController.myModel).toEqual('World');
    });
});

After we’ve refactored our code, we could make sure that we haven’t broken anything and this could be accomplished using Protractor. A single problem is that we extract some elements by their model but now it is vm.myModel, not myModel . After ironing out this wrinkle launching Protractor e2e tests should end up in success.

AngularJS Nested Scopes

After we’ve introduced AngularJS Controller As syntax, it’s high time to see how it helps solve the nested scope problem. The HTML snippet below shows how to use the syntax in this case. While it’s possible to name each controller as vm because each of the controllers attached to a different scope, we use more clear names for controllers to prevent name collisions.

<section ng-controller="ParentController as parent">
    <h4>Parent Scope</h4>
    <p>{{parent.onlyParent}}</p>
    <p>{{parent.myModel}}</p>
    <article ng-controller="ChildController as child">
      <h5>Child Scope</h5>
      <p>{{child.onlyChild}}</p>
      <p>{{child.myModel}}</p>
      <p>{{parent.onlyParent}}</p>
      <p>{{parent.myModel}}</p>
    </article>
</section>

The code for controllers is similar to the above one for HelloController and can be found here. The scopes look like in the pictures below. The first is for the parent scope.

 

And the second one is for the child scope.

 

Testing is done in the similar way to the HelloController  and test examples can be found here. Also, is we talk about end-to-end testing using Protractor, it is easier to extract elements by their model because the latter contains the name of the controller, so we don’t need to manipulate arrays of elements with the same model name. 

Summary

 In this tutorial we learned how to use AngularJS Controller As syntax. In the next post we’ll talk about AngularJS components introduced by version 1.5. 

Resources

  1. What are scopes
  2. Understanding Controllers
  3. Digging into Angular’s “Controller as” Syntax
  4. AngularJS’s Controller As and the vm Variable
Reference: AngularJS Tutorial: AngularJS Controller As Syntax from our WCG partner Dmitry Noranovich at the Java and JavaEE blog blog.

Dmitry Noranovich

Dmitry teaches physics and moonlights as a Java developer. He is experienced in building Web applications using a full-profile application server as well as in Java SE. Also he is fond of teaching on-line programming courses
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button