Tuesday, June 14, 2016

TypeScripting AngularJS 1.x - Routing

Though we say we are developing web apps, navigation is really important in it. It is always advisable to have separate urls for different screens though the entire page won't reload when we change the screens.
In AngularJS there are mainly 2 ways to achieve routing. One with the routing library coming with framework and other using ng-route and other is via ui-router. Comparison between those is a big thing and not coming  under this post. Here we are going to see how routing can be setup in the TypeScript way using the library inside the Angular framework.

TypeScript has definitions for ng.Route library. If we add that we can get the routing related types such as ng.route.IRouteProvider. But as always we can setup the route in JavaScript style inside TypeScript file. Since every valid JavaScript is valid TypeScript, there won't be any compilation issue. But the problem is maintainability it its a big app. If we  change a route or pass wrong argument, there won't be any warning / error in JavaScript way. But if its written in TypeScript way, it won't compile on wrong parameter type or names. If we are using Visual Studio, TypeScript way can show the  suggestions on what are the options available, when we configure routing.

Lets see how its done in code.

JavaScript way

angular.module('HRApp').config(['$routeProvider',
    function routes($routeProvider: ng.IRouteProvider) {
        $routeProvider
            .when('/add', {
                template: '<add-employee></add-employee>',
                caseInsensitiveMatch: true
            })
.           .when("/Company/:companyId/Employee/:empId", {
                template: '<employee-detail></employee-detail>'
            })
            .otherwise({
                template: '<employee-detail></employee-detail>'
            });     } ]);
Here how do we know, what are the properties available for the object being passed to .when() method? Whatever we pass, it never complain. But it never give us the required behavior. We may need to run the app 2-3 times to make sure the spelling and all are correct. Lets see in TyprScript.

TypeScript way

module HRApplication {
    "use strict";
    export class HRModule {
        app: ng.IModule;
        constructor() {
            this.app = angular.module("HR", ["ngRoute"]);
        }
        setupServices(): void {
        }
        setupDirectives(): void {
        }
        setupRoutes(): void {
            this.app.config(["$routeProvider",
                function ($routeProvider: ng.route.IRouteProvider) {
                    $routeProvider.when("/add", new AddEmployeeRoute())
                        .when("/Company/:companyId/Employee/:empId", new EmployeeDetailRoute())
                        .when("/Company/:companyId", new EmployeeDetailRoute())
                        .otherwise(new EmployeeDetailRoute());
                }]);
        }
    }
    var hrApp: HRModule = new HRModule();
    hrApp.setupServices();
    hrApp.setupDirectives();
    hrApp.setupRoutes();
}

What about the AddEmployeeRoute() and other route classes. Those should implement the ng.route.IRoute. Below is the code
class AddEmployeeRoute implements ng.route.IRoute {
    template = "<add-employee></add-employee>";
    caseInsensitiveMatch = true;
}
class EmployeeDetailRoute implements ng.route.IRoute {
    template = "<employee-detail></employee-detail>";
}


The advantage here is, if we inherit from IRoute we will get intellisense for the available properties such as caseInsensitiveMatch. If we are writing in JavaScript way, we never get a chance to ensure its correctly spelled unless we run the application.

Happy TypeScripting...

No comments: