Creating AngularJS Directives Using Typescript

Converting AngularJS Directive from JavaScript to TypeScript can be tricky sometimes, you can try both approaches with class or without class, both of them have benefits and pitfalls, here I am going to use class implementation to create directive.

Directive TypeScript Structure

The structure of angular directive in typescript is simple, all we need to do is to create a class and have directive logic inside it with just one more static method, which we will talk below.

module app {
    'use strict';


    class TestDirective implements ng.IDirective {
        /*
         * This static method is needed to return instance
         */
        static instance() : ng.IDirective {
            return new TestDirective;
        }


        restrict = 'E';
        link(scope : ng.IScope, elements : ng.IAugmentedJQuery, attrs : ng.IAttributes) {
              //your code
        }
    }

    angular.module('app')
            .directive('testDirective', TestDirective.instance);

}

Here you can see we are creating a static method called instance and returning the new instance of the class itself, and calling that static method in angular directive declaration syntax.

Note: I am using the angular.d.ts type definition file from definitelytyped.org.

Progress Bar Directive Example using TypeScript

In this section we are going to create progress-bar directive, this directive will be an Html element called progress-bar and will generate simple bootstrap progress bar.

app.html( HTML Markup )

We are going to need Bootstrap, jQuery and Angular in our app, let's import them using CDN.

<!doctype html>
<html lang="en" ng-app="app">
<head>
    <meta charset="UTF-8">
    <title>Progressbar</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
<body>
<div class="container">
    <div class="row">

        <h1>ProgressBar Directive using Angular and Typescript</h1>
        <progress-bar></progress-bar>

    </div>
</div>

<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="js/app.js"></script>
<script src="js/progressbar.directive.js"></script>
</body>
</html>

TypeScript

I am going to create two typescript files, one for app module and other for the progress-bar directive.

app.ts

///<reference path="../typings/angularjs/angular.d.ts"/>
module app {
    'use strict';

    angular.module('app', []);
}

app.js ( complied output )

///<reference path="../typings/angularjs/angular.d.ts"/>
var app;
(function (app) {
    'use strict';
    angular.module('app', []);
})(app || (app = {}));
//# sourceMappingURL=app.module.js.map

progressbar.directive.ts

module app {
    'use strict';

    interface IProgressbarScope extends ng.IScope {
        value : number;
    }

    class Progressbar implements ng.IDirective {

        static instance() : ng.IDirective {
            return new Progressbar;
        }

        restrict = 'E';
        
        template = `
                <div class="progress">
                  <div class="progress-bar" role="progressbar" aria-valuenow="{{ value }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ value }}%;">
                    <span class="sr-only">60% Complete</span>
                  </div>
                </div>
                <div>
                    <span>{{ value }}% Completed</span>
                </div>
        `;
        link(scope : IProgressbarScope, elements : ng.IAugmentedJQuery, attrs : ng.IAttributes) {

                scope.value = 0;
                setInterval(() => {
                    scope.$apply(() => {
                        if(scope.value >= 100) {
                            scope.value = 0;
                            return;
                        }
                        scope.value = scope.value + 10;
                    });
                }, 1000);
        }
    }

    angular.module('app')
            .directive('progressBar', Progressbar.instance);

}

Note: I am using tick (`) not single quote (') in template syntax.

progressbar.directive.js ( compiled output )

var app;
(function (app) {
    'use strict';
    var Progressbar = (function () {
        function Progressbar() {
            this.restrict = 'E';
            this.template = "\n                <div class=\"progress\">\n                  <div class=\"progress-bar\" role=\"progressbar\" aria-valuenow=\"{{ value }}\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width: {{ value }}%;\">\n                    <span class=\"sr-only\">60% Complete</span>\n                  </div>\n                </div>\n                <div>\n                    <span>{{ value }}% Completed</span>\n                </div>\n        ";
        }
        Progressbar.instance = function () {
            return new Progressbar;
        };
        Progressbar.prototype.link = function (scope, elements, attrs) {
            scope.value = 50;
            setInterval(function () {
                scope.$apply(function () {
                    if (scope.value >= 100) {
                        scope.value = 0;
                        return;
                    }
                    scope.value = scope.value + 10;
                });
            }, 1000);
        };
        return Progressbar;
    })();
    angular.module('app')
        .directive('progressBar', Progressbar.instance);
})(app || (app = {}));
//# sourceMappingURL=progressbar.directive.js.map

That's it, guys, you can obviously change the logic to suit your needs, I am using this simple example to demonstrate just how easy it is to create AngularJS directives in TypeScript.

If you have any questions, ask us in the comment section or create new thread in the forum.

Something to say? Tell us in comment section.