Subscribe to our Newsletter

Receive our news and insights

Blog / Software Product Development  

Component Based Development With Angular and Typescript

A Picture of Rodrigo Pimentel
April 07, 2015 | Topic: Software Product Development  
Component Based Development With Angular and Typescript

Modern web applications are increasingly required to provide a user experience closer to that of a native application. Web development therefore increasingly relies on single page applications (SPA). This rise in SPA popularity brings several frameworks and tools to make our life easier.

 Component-Based Development Practices

As Wikipedia states “component based development, is a branch of software engineering that emphasizes the separation of concerns in respect of the wide-ranging functionality available. It is a reuse-based approach to defining, implementing and composing independent components”.

As applications grow, its source may host non-business logic (common functions, widgets, grids, extensions, etc), hosting this code at our application core is a bad practice, particularly for large applications. We should make the effort to ensure that the core of our application is only for business logic, and separate the rest into generic and reusable components. Every component should come with tests, documentation and examples of usage, which should be easy to install, configure and extend.

Why TypeScript?

Why not! TypeScript is a superset of JavaScript, it can run plain JS but it also adds a lot of aspects on top of it (interfaces, standard OOP, built in support for modules) to assist us in writing predictable and maintainable code. JS will have to wait for the upcoming ES6 (Find out more here:

The Basics Of Creating A Component

The following section of this blog post will outline a typical angularjs widget using a service and a directive (we could be using other frameworks instead of Angular).

Let’s create a click counter button widget. The namespace for our module is MyWidgets.ClickCounter, I like the ‘MyWidgets’ namespace first because it can contain more widgets like our ClickCounter.

<b>File: clickCounterBase.ts</b>
module MyWidgets.ClickCounter {
"use strict";
// remember the path to the library for importing html templates too
var libraryCurrentPath: string = $("script[src$=’clickCounterBase.js']")[0]
.getAttribute("src").replace("clickCounterBase.js", "");
export interface IClickCounterService {
clickCounter: number;
clickMe: () =&gt; void;

Let’s implement an Angular service following the IClickCounterService interface. It is just a one var and one function service:

<b>File: clickCounterService.ts</b>
/// &lt;reference path='./clickCounterBase.ts' /&gt;
module MyWidgets.ClickCounter {
"use strict";
export class ClickCounterService implements IClickCounterService {
public clickCounter: number = 0;
public incrementCounter: () =&gt; void;
public static $inject = ["$rootScope"]; // will use $broadcast for unit testing
constructor($rootScope: ng.IRootScopeService) {
this.incrementCounter = (): void =&gt; {
// broadcast a signal for testing
angular.module("clickCounterService", []).service("clickCounterService", [
"$rootScope", ($rootScope: ng.IRootScopeService): MyWidgets.ClickCounter =&gt;
new ClickCounterService($rootScope)

We have a counter starting at 0, a function that increments the counter at every call and broadcasts a signal about it. Let’s test this!

File: clickCounterTests.ts
describe("Test clickCounterService", (): void =&gt; {
   angular.module("TestApp", ["clickCounterService"]);
   var clickCounterService: MyWidgets.ClickCounter.IClickCounterService;
   var $rootScope: any;
   beforeEach(inject(($injector: any): void =&gt; {
       clickCounterService = $injector.get("clickCounterService");
       $rootScope = $injector.get("$rootScope");
       spyOn($rootScope, "$broadcast");
   it("should increment click counter", (): void =&gt; {
       // the counter starts with 0, so it should be 1 after the increment.

And finally our directive and template.

File: clickCounterService.ts
module MyWidgets.ClickCounter {
	"use strict";
   export class UiClickCounter implements ng.IDirective {
       public templateUrl: string;
       public replace: boolean;
       public restrict: string;
       public scope: any;
       public link: ng.IDirectiveLinkFn;
       public static $inject = ["$timeout", "clickCounterService"];
       constructor($timeout: ng.ITimeoutService, clickCounterService: IClickCounterService) {
           this.scope = {};
           this.templateUrl = libraryCurrentPath + "uiClickCounter.html";
           this.replace = true;
           this.restrict = "E";
  = (scope: any, iElement: ng.IAugmentedJQuery): void =&gt; {
	// called every time the button is clicked
	scope.increment: () =&gt; void = (): void =&gt; { clickCounterService.incrementCounter() 
	   // will update view counter when the clickCounterService broadcast an increment.
               var update: () =&gt; void = (): void =&gt; {
                   $timeout((): void =&gt; {
                       scope.clickCounter = clickCounterService.clickCounter;
               scope.$on("clickCounterService:incremented", update);
   angular.module("clickCounterDirective", []).directive("uiClickCounter", [
       "$timeout", "clickCounterService",
       ($timeout: ng.ITimeoutService, clickCounterService: IClickCounterService):
       MyWidgets.ClickCounter =&gt; new UiClickCounter($timeout, clickCounterService)
File: uiClickCounter.html
<button> {{ scope.clickCounter }} </button>

Ready To Go!

Our component is done!. We have a module that can be imported to our main angular application and a directive that will contain our widget. The next step for integration is to use Gulp (for compilation, minification, TSLint, etc…) and Bower so the package can be easy to import and update. Our component should live in its own repository and come with documentation and an example application as well. What a great way to develop maintainable and reusable software!


Related Services



The leaders we need to navigate the COVID-19 storm


April 23 / 2020

1 Stars2 Stars3 Stars4 Stars5 Stars

As we gradually get used to our new COVID-19 reality, daily life from just a few weeks ago now feels like a lifetime away. For businesses this has created,...

Read post