Tuesday, May 3, 2016

TypeScripting AngularJS 1.x - Define module - improvements for big enterprise apps

Improvements for enterprise apps

We have see that there is a typed way to define modules and setup the Angular constructs such as services, controllers etc...This works great in small apps. But there is a problem, if we are developing an big enterprise app with many developers adding new controllers, directives frequently. In that situation, everybody will be competing for the one app / module file.

Below can be our aim when designing TypeScript Angular module class.
  • No need to repeat the ng-app name in every file.
  • There should be one central place for knowing what are the components registered.
  • Every angular component registered in the system should be testable using dependency injection.

How to fix it?

What if we expose a method in the Module to registerController, Directive etc...Those methods can be called by each file which contains different Angular components to register themselves? The object of Module can be exposed via singleton. Lets see the code below for the Angular module wrapper class.

CountryModule.ts

module CountryApplication {
    "use strict";
    export class CountryModule {
        //Do not expose the property as it is not expected to change from outside.
        private static currentCountryModule: CountryModule;
        public static getInstance(): CountryModule {
            return CountryModule.currentCountryModule;
        }
        private app: ng.IModule;
 
        constructor() {
            this.app = angular.module("CountryApp", []);
            CountryModule.currentCountryModule = this;
        }
        /** Acts as central place for registration. But somebody adds new controller they don't need to edit this file.
        */
        registerService(name: string, serviceConstructor: Function): void {
            this.app.service(name, serviceConstructor);
        }
        registerController(name: string, controllerConstructor: Function): void {
            this.app.controller(name, controllerConstructor);
        }
    }
    var hrApp: CountryModule = new CountryModule();
}

The code is self explanatory. We are just wrapping the actual Angular application inside CoutryModule class. Lets see how services can register to the ng application.

CountryMetadataService.ts

module CountryApplication {
    export class CountryMetaDataService {
        employees: Array<Country> = new Array<Country>(
            { id: 1, DisplayName: "India", Currency: "Indian Rupee", CurrencySymbol: "R" },
            { id: 2, DisplayName: "United States", Currency: "Dollar", CurrencySymbol: "$" }
        );
        GetAll(): Array<Country> {
            return this.employees;
        }
    }
    // Registering with angular app name in every file is difficult to maintain.
    // angular.module('CountryApp').service("CountryMetaDataService", CountryMetaDataService);
    CountryModule.getInstance().registerService("CountryMetaDataService", CountryMetaDataService);
}

An end to end template can be found in Github.com. This will get more scenarios on how to use TypeScript in AngularJS applications in TypeScript way.

Welcome to enterprise web app development.

No comments: