Updating $scope Data in Asynchronous Functions

One of the many lovely things about Angular is the fluid two-way data binding that we get with the framework. Although not entirely perfect when it comes down to performance, it saves us quite a lot of timeΒ and effort when writing web applications.

When it comes to asynchronousy, however, it should be noted that doing changes to your $scope data does not propagate to the view implicitly (!). In other words, if you do a change to a $scope variable from asynchronous context, the change is not reflected in the view. Let’s look at an example. Consider the following controller that uses JavaScript’s asynchronous setInterval function to update a counter every second:

function Ctrl ($scope) {
    $scope.counter = 0;
    
    setInterval(function() {
        $scope.counter++;
    }, 1000);
}

This code looks pretty good and dandy, right? Unfortunately, no. Although the counter does get updated every second, it does not propagate the change to the view. There are a couple of ways to solve this issue.

Invoking $apply Manually

The simplest and most straightforward way is to invoke $apply manually in the asynchronous context. Consider the following change to our initial example (lines 5 – 7):

function Ctrl ($scope) {
    $scope.counter = 0;
    
    setInterval(function() {
        $scope.$apply(function () {
            $scope.counter++;
        });
    }, 1000);
}

This change will force the counter updates through to the view.

Using Angular’s Asynchronous Services

This approach is case specific. For instance, you can use the services $interval or $timeout, which actually behind the scenes invoke $apply – relieving you from doing so manually. Considering our initial example, we can therefore inject and use $interval in our controller instead:

function Ctrl ($scope, $interval) {
    $scope.counter = 0;

    $interval(function () {
        $scope.counter++;
    }, 1000);
}

As the previous approach, this will propagate the counter updates to the view. I recommend using Angular’s services wherever this is possible and seems appropriate to the case at hand. However, always keep in mind that such services invoke $apply for you behind the scenes.

Hope you enjoyed this Sunday’s little reading! πŸ™‚

Advertisements

Proper Dependency Injection in Your AngularJS TypeScript Apps

I’ve witnessed quite a lot of legacy AngularJS TypeScript code (yes, including my very own) where dependency injection is done in an impractical way. The most common way of doing dependency injection, is by manually injecting the dependencies while loading your AngularJS components and their accommodating TypeScript classes. What this basically means is that, while injecting a dependency, you have to do this three times (!). Not only that, all three times have to be similar in order for the injection (string matching) to work. Consider the following example:

 
angular.module("myApp", []).controller("MyController", ["$scope", "MyService", ($scope, MyService)
    => new Application.Controllers.MyController($scope, MyService)]);
module Application.Controllers {
 
    import Services = Application.Services;
 
    export class MyController {
 
        scope: any;
        myService: Services.IMyService;
         
        constructor($scope: ng.IScope, myService: Services.IMyService) {
            this.scope = $scope;
            this.myService = myService;
        }
    }
}

MyController is a class that takes in two dependencies – $scope and MyService. However, in the first code block, the injection itself is written three times (lines 1 and 2). Not only does this result in a maintenance hell, it greatly affects the readability of the code.

So, how do we solve this issue? Simple, we use AngularJS’ $inject property to do the injection in our TypeScript class. In MyController, we statically use $inject and define the dependencies like so (line 10):

module Application.Controllers {
 
    import Services = Application.Services;
 
    export class MyController {
 
        scope: any;
        myService: Services.IMyService;
        
        static $inject = ["$scope", "MyService"];

        constructor($scope: ng.IScope, myService: Services.IMyService) {
            this.scope = $scope;
            this.myService = myService;
        }
    }
}

And then simply change the wiring like so:

 
angular.module("myApp", []).controller("MyController", Application.Controllers.MyController);

Notice how elegant the wiring looks? No explicit injection that we need to worry about, all we need is to inspect the class itself to find the dependencies.

I will speak at JavaZone 2014

I’m very happy and excited to announce that I will be speaking at JavaZone 2014! If you did not know already, JavaZone is the largest IT conference in Norway. Up to 2500 software engineers and developers gather each year in Oslo during September to attend 3 days packed with presentations, lightning talks and workshops!

I will be doing a 60 minute presentation on the topic “TDD with AngularJS and TypeScript”. Make sure to book your ticket today and I will see you in September! πŸ™‚

I will speak at the Trondheim Developer Conference

I’m thrilled to announce that I will be speaking at the Trondheim Developer Conference in October this year! If you didn’t know already, this is an awesome conference arranged once a year by technology user groups in the Trondheim area, Norway. Among the user groups behind the conference is the Norwegian .NET User Group, JavaBin Trondheim, Trondheim XP & Agile Meetup and many more!

The conference kicks off on October 27th, and the topic of my talk is “TDD with AngularJS and TypeScript”. Make sure to book your tickets today, and I will see you in October!

tdc

Directives in AngularJS

So I thought that I’d make a detailed post about directives in AngularJS. If you’ve just started out with AngularJS, chances are you are curious to learn about this powerful feature. Directives are great if you want to create your own custom HTML elements. In fact, directives give us a glimpse of the future. In HTML 5, we got new elements and the goal is to increase this in the future so you won’t need to use the class attribute so often. Learning to use directives may seem a bit complex for the AngularJS beginner, but trust me, it’s really easy once you get the hang of it. Using directives isn’t really mandatory when you work with AngularJS, unfortunately this leads to developers not using this feature. I hope to change that with my post, and make you use it if you don’t already.

A directive can be written in four different ways; as an element, attribute, comment or class. The best practice is to write it as an element or attribute. Here are the four ways a directive can be written in HTML:

<my-directive></my-directive>
<div my-directive></div>
<!-- directive: my-directive -->
<div class="my-directive"></div>

The directive is loaded into Angular at the start up of a web application. Usually in a bootstrap.js where you load your other Angular components, such as controllers and factories. The directive is loaded like such (line 2):

var myApp = angular.module('myApp', []);
myApp.directive('myDirective', myDirective);
function myDirective() {
    return ""
};

Note that in the HTML we called the directive my-directive, this is transformed to camel case and therefore we load the directive as myDirective in Angular. As you can see, this directive doesn’t do much. It simply returns an empty string. A directive function has up to eleven different attributes that can be used. It has priority, template, templateUrl, replace, transclude, restrict, scope, controller, require, link and compile. By no means will you be using all of those attributes at once, usually you would use three to four attributes depending on your web application. I’m going to give a short description of each attribute.

Priority defines the order of how the directives get compiled, this is the case when you have created multiple directives on a single DOM element. Directives with a greater priority number get compiled first.

Template is used to add your HTML template code that you want to be shown, and templateUrl is a URL to your HTML template.

Replace is used to either replace the directive element with your HTML template (true) or to replace the contents of it (false). This is by default set to false.

Transclusion is a sibling of the isolate scope (which I will explain soon), which means that it’s bound to the parent scope. This makes the content of your directive have its own private state. transclude can be set to true (transclude the content) or to ‘element’ (transclude the whole directive).

Restrict is used to define the type of your directive. It can be set to E (element), A (attribute), M (comment) or C (class). The default value is A.

By using scope, you can define an isolated scope for your directive content. If scope is not used, the directive will use the parent scope by default. Scope can be set to true (new scope created for the directive), false (use parent scope), pass in scope for two-way binding, pass in type and other custom attributes.

Controller is used if you want your directive to have its own controller. You simply set it with the name of the controller that you’ve loaded in Angular.

Use require if you want to have a dependency on other directives, in that case inject the dependency directive’s controller as the fourth argument in the link function (which we will get to shortly). require is set to the name of the dependency directive’s controller, if there are several dependency directives, then an array is used containing the controller names.

Link is used to define directive logic, it is responsible for registering DOM listeners and updating the DOM. Link takes in several arguments, and it is here where you define your directive logic. However, this attribute is unnecessary if you are using the controller attribute and got the directive logic inside a controller.

Compile is used to transform the template DOM. ngRepeat is an example of a template DOM that needs to be transformed into HTML. Since most directives do not transform DOM templates, this attribute is not often used. Compile takes in several arguments.

For more information on each of the directive attributes, I suggest checking the AngularJS documentation.

Time for examples of usage, let’s assume we have written the following directive in the HTML:

<my-directive></my-directive>

Now, in the JavaScript this directive is implemented like this (line 3):

var myApp = angular.module('myApp', []);
myApp.directive('myDirective', myDirective);
function myDirective() {
    return {
    restrict: 'EA',
    template: '<div>Hello World!</div>'
    }
};

I set restrict to 'EA' on purpose, to show you that you can make the directive implementation work on both an element and an attribute if you wish. This is a simple directive that returns a template div with the text “Hello World!”. Now, we can extract this template to a file:

function myDirective() {
    return {
    restrict: 'EA',
    templateUrl: 'helloWorld.html'
    }
};

And the content of helloWorld.html:

<div>Hello World!</div>

Let’s put our directive inside a controller:

<div ng-controller="myController"> 
<my-directive></my-directive>
</div>

The controller is simple, it looks like this:

myApp.controller('myController', myController);
function myController($scope) {
    $scope.message = "Hello World!";
};

Now, we change the directive:

function myDirective() {
    return {
    restrict: 'EA',
    template: '{{message}}'
    }
};

Can you guess what happens? The directive uses the parent controller and scope, and returns the message defined in the controller – “Hello World!”. Now let’s create a controller specifically for our directive, and call it myDirectiveController:

myApp.controller('myDirectiveController', myDirectiveController);
function myDirectiveController($scope) {
    $scope.directiveMessage = "Hello World!";
};

And change the directive to use this controller and an isolated scope:

function myDirective() {
    return {
    restrict: 'EA',
    scope: true,
    controller: 'myDirectiveController',
    template: '{{directiveMessage}}'
    }
};

Again, the directive will return the message “Hello World!”, this time from its own controller. If you want to pass parameters from the parent controller, that’s possible. Let’s assume that the parent controller myController has a messages collection, that we loop through in the HTML:

<div ng-controller="myController"> 
<div ng-repeat="message in messages">
<my-directive message="message"></my-directive>
</div>
</div>

We loop through the collection and pass each message to the directive. The directive then looks like this:

function myDirective() {
    return {
    restrict: 'EA',
    scope: {
    message: '='
    },
    controller: 'myDirectiveController',
    template: '{{message}}'
    }
};

The message is passed to the directive controller, by setting the message attribute in the scope to ‘=’. This can be done differently, you can type message="myMessage" in the div (instead of message="message"), in that case you need to add message: '=myMessage' in the scope. Using ‘=?’ means that a parameter is optional. Another thing you can do is send in type. You use the type attribute in the HTML, then add type: '@' in the scope.

Another thing you can do of course, is to use the link attribute to define your logic there. Let’s do that:

function myDirective() {
    return {
    restrict: 'EA',
    link: function(scope, element, attributes) {
        element.addClass('alert');
    }
};

Link takes in current scope as argument, the directive element itself and custom attributes that you can pass in. Link uses jQuery Lite, a lighter version of jQuery. You can do jQuery operations inside of this function, in this case we are adding a css class alert to the directive element. You can do a lot of other different things with directives, for more I suggest checking out the AngularJS documentation.

I’ve explained most of what you need to know about directives. When you write directives, I recommend that you create controllers specifically for the directives. Put all logic in the controllers, and do not use the link function. Avoid jQuery operations and stick to pure Angular. That way you keep your code clean and nicely isolated. I hope that this gives you a good introduction to directives, and helps you get started using them. As you can see, it’s not that hard, is it? πŸ™‚

I will speak at the HTML5 Developer Conference in San Francisco

I will be speaking at the HTML5 Developer Conference in San Francisco this year! I received this exciting news yesterday night at around 02:00 AM in the morning. I’m glad that I didn’t read the e-mail at that time, otherwise I wouldn’t have slept because of all the excitement! If you didn’t already know, this is the largest JavaScript and HTML5 conference in the world. It’s an awesome conference that spans one day with training sessions spanning four days in advance. The topic of my talk is titled “TDD with AngularJS and TypeScript”. I will get further details surrounding the talk eventually, whether it will be a workshop session or regular talk (or both).

Make sure you to book your tickets today, I’ll see you in ‘frisco this May! πŸ™‚

When Two Forces Meet (AngularJS, TypeScript)

AngularJS is largely growing in popularity among front-end developers. According to a JavaScript developer survey conducted in 2013, it was shown that AngularJS was among the top two most used JavaScript frameworks. In a world where there are close to 17 million MVC JavaScript frameworks, this puts AngularJS on top of the game. On the other end of the scale, while not as widely used as AngularJS, TypeScript is slowly becoming the de facto compiler language for writing object oriented JavaScript. So what happens when these two forces meet? A great power emerges! We learned from Uncle Ben (Spider-Man movie) that with great power, comes great responsibility. In this tutorial, I show how these two forces can be combined to produce an ultimate web application.

Capture

Setup

As a .NET developer, I use Visual Studio 2013 and the TypeScript plugin for Visual Studio. This is what I recommend that you use unless you are for some reason against the Windows platform. Then using the NuGet packet manager, you can install the necessary AngularJS core files. In addition to this, make sure to install the AngularJS TypeScript definitely typed files which provides typed AngularJS components that can be used in your TypeScript code.

Bootstrapper

In AngularJS you create an app.js where you load your modules, controllers, factories and directives. You do almost the same thing in TypeScript, the only difference here is that your controllers, factories and directives are represented as TypeScript classes in an app.ts file. So your app.ts can look like this:

var appModule = angular.module("myApp", []);

appModule.controller("MyController", ["$scope", "MyService", ($scope, MyService)
    => new Application.Controllers.MyController($scope, MyService)]);

appModule.factory("MyService", ["$http", "$location", ($http, $location)
    => new Application.Services.MyService($http, $scope)]);

appModule.directive("myDirective", ()
    => new Application.Directives.MyDirective());

Note the usage of lambda, we do this to reserve lexical scope. Always make sure to use this instead of function() in TypeScript. Now that you’ve set up your bootstrapper, in the next sections we’ll look at how the individual AngularJS components are written in TypeScript.

Controller Classes

Controllers are written as classes, so your MyController.ts class can look like this:

module Application.Controllers {

    import Services = Application.Services;

    export class MyController {

        scope: any;
        myService: Services.IMyService;
	    data: any;
		
        constructor($scope: ng.IScope, myService: Services.IMyService) {
            this.scope = $scope;
            this.myService = myService;
	        this.data = [];
        }

        private GetAll() {
            this.myService.GetAll((data) => {
                this.data = data;
            });
        }
	}
}

Factory Classes

Similarly, factories or services are written as classes. So your MyService.ts class can look like this:

module Application.Services {

    export interface IMyService {
        GetAll(successCallback: Function);
    }

    export class MyService {

        http: ng.IHttpService;
        location: ng.ILocationService;

        constructor($http: ng.IHttpService, $location: ng.ILocationService) {
            this.http = $http;
            this.location = $location;
        }

        GetAll(successCallback: Function) {
            this.http.get(this.location.absUrl()).success((data, status) => {
                successCallback(data);
            }).error(error => {
                successCallback(error);
            });
        }
	}
}

Note the interface IMyService here. Always use interfaces to abstract your classes in TypeScript, just as you would usually do in a typed language.

Directive Classes

Directives are also written as classes. So your MyDirective.ts class can look like this:

module Application.Directives {

    export class MyDirective {

        constructor() {
			return this.CreateDirective();
        }

        private CreateDirective():any {
            return {
                restrict: 'E',
                template: '<div>MyDirective</div>
            };
        }
    }
}

Databinding with Alias

Finally, to be able to use your TypeScript classes from your HTML, you need to databind using alias. So your HTML can look like this:

<html data-ng-app="myApp">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>
<body>
	<div data-ng-controller="MyController as mc">
		<div data-ng-repeat="element in mc.data">
			<label>{{element}}</label>
		</div>
		<my-directive></my-directive>
	</div>
</body>
</html>

Databinding without Alias

Unfortunately, databinding with alias does not work in Internet Explorer 8. Neither do directive elements(!). To make it work in IE 8, you need to change your HTML so it looks like this:

<html xmlns:ng="http://angularjs.org" id="ng-app" data-ng-app="myApp">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--[if lte IE 8]>
            <script>
                document.createElement('ng-include');
                document.createElement('ng-pluralize');
                document.createElement('ng-view');
                document.createElement('my-directive');
                document.createElement('ng:include');
                document.createElement('ng:pluralize');
                document.createElement('ng:view');
            </script>
            <script src="libs/es5-shim/es5-shim.js"></script>
            <script src="libs/JSON/json3.js"></script>
        <![endif]-->
</head>
<body>
	<div data-ng-controller="MyController">
		<div data-ng-repeat="element in data">
			<label>{{element}}</label>
		</div>
		<my-directive></my-directive>
	</div>
</body>
</html>

Now if you want to call your TypeScript class methods from your HTML in IE 8 without an alias, then you need to hook your methods (and everything else they use) onto the Angular scope. This can be done like the following, in MyController.ts:

module Application.Controllers {

    import Services = Application.Services;

    export class MyController {

        scope: any;
		
        constructor($scope: ng.IScope, myService: Services.IMyService) {
            this.scope = $scope;
            this.scope.myService = myService;
			this.scope.data = [];
			this.scope.GetAll = this.GetAll;
        }

        GetAll() {
            this.scope.myService.GetAll((data) => {
                this.scope.data = data;
            });
        }
	}
}

Notice how everything is hooked onto scope. That way, databinding is correctly achieved in IE 8, and you are able to call your GetAll() method from the HTML by simply typing GetAll() without alias.

Hope you enjoyed this tutorial! I’m planning on holding a workshop about this and doing TDD at this year’s Norwegian Developers Conference 2014, so make sure to book your tickets! πŸ™‚