Using TypeScript generated JavaScript in HTML and populating data

This is the continuation to my Creating AngularJS service and controller for Products blog and in this blog we will be looking at wiring the ProductService and ProductController to HTML. I have not used any complex AngularJS directives here I am bingding the products array that we retrieve from ProductService in to a table by using ng-repeat directive. Here is the code in the HTML file.

<html>   
    <script src="node_modules/angular/angular.js"></script> 
    <script src="node_modules/angular-ui-grid/ui-grid.js"></script>
    <script src="node_modules/jquery/dist/jquery.js"></script>     
     <script src="HelloWorld.js"></script>
     <script src="app/Models/Products/Product.js"></script>
     <script src="app/Service/Products/ProductsRepository.js"></script>
     <script src="app/Controllers/Products/productController.js"></script>
     <script src="app/app.js"></script>     
    <body ng-app="jaysmodule">                
        <input type="button" onclick="SayHello();" value="Hello" />               
        {{30+60}}
        <div ng-controller="ProductsController">
            <div>  
                <labl><b> Sample Demo to NG Grid</b></labl>  
            </div>  
            <table>
                <thead>
                    <tr>
                        <th class="productid">Product ID</th>
                        <th class="productname">Product Name</th>
                        <th class="productcode">Product Code</th>
                        <th class="price">Price</th>
                        <th class="productdecription">Description</th>
                    </tr>
                </thead>
                <tbody>
                    <tr ng-repeat="item in Products">
                        <td><input type="text" ng-disabled="saving" title="ID" ng-model="item.ProductId" ng-model-options="{updateOn:'blur'}" /></td>
                        <td><input type="text" ng-disabled="saving" title="ProductName" ng-model="item.ProductName" ng-model-options="{updateOn:'blur'}" /></td>
                        <td><input type="text" ng-disabled="saving" title="ProductCode" ng-model="item.ProductCode" ng-model-options="{updateOn:'blur'}" /></td>
                        <td><input type="text" ng-disabled="saving" title="ProductPrice" ng-model="item.Price" ng-model-options="{updateOn:'blur'}" /></td>
                        <td><input type="text" ng-disabled="saving" title="ProductDescription" ng-model="item.Description" ng-model-options="{updateOn:'blur'}" /></td>
                    </tr>
                </tbody>
            </table>
        </div>
    </body>
</html>

The html output will be as below.
Products_Html

Creating AngularJS service and controller for Products

In this blog we will see how we create a instance of ProductController in the App.ts file, this will be the starting point in the VSCode / Visual Studio code for initializing AngularJS module, services, models and controllers.

The following is the code that initializes the AngularJS module with instance to ProductService and ProductController.

module app {
    angular.module("jaysmodule",['ui.grid'])
    .service("productService", ["$q",
                function ($q) {
                    return new app.Service.Products.ProductService($q, "Static");
                }])
}

Let’s me explain how the instance of ProductService is created now. The following is the code for creating service

module app {
    angular.module("jaysmodule",['ui.grid'])
    .service("productService", ["$q",
                function ($q) {
                    return new app.Service.Products.ProductService($q, "Static");
                }])
}

If you have identified, the ProductService constructor code that we discussed this requires 2 parameters namely

  • $q: ng.IQService – This AngularJS service is used to have the Asynchronous implementation, this sevice provides implementation for deferred, resolve and reject that will come handy when you call a external service.
  • repoType: string – If you have noticed, ProductService extends ProductRepositoryManager which is responsible for creating instance of the repository service based on the string parameter passed, when you pass “Static” it creates instance of the ProductStaticRepository and when “Service” is passed it creates instance of ProductServiceRepository.
  • While creating instance of ProductService instance we are creating instance of the ProductStaticRepository by passing “Static”. This will be the case when the business service development teams is not ready with the service while the UI team is ready to test their implementation. So until the business service is ready we can use the static repository for testing our AngularJS UI implementations. So by the time when actual service is ready we just need to pass “Service” as parameter to ProductRepositoryManager which provides the instance of ProductServiceRepository that calls the business sevices.

Let’s me explain how the instance of ProductController is created now. The following is the code for creating controller

module app {
    angular.module("jaysmodule",['ui.grid'])
    .service("productService", ["$q",
                function ($q) {
                    return new app.Service.Products.ProductService($q, "Static");
                }])
    .controller("ProductsController", ["$scope", "productService", function($scope: app.Controllers.Products.IProductsController<app.Models.Products.Products>, productService)
    {
        var controller = new app.Controllers.Products.ProductsController($scope, productService);
        controller.$scope.ReadItems();
        return controller;
    }]);
}

When you look at the controller code, it takes the instance of the product service and $scope as instance of app.Controllers.Products.IProductsController, as IProductsController extends ng.IScope AngularJS will compile without any issues and the important one to understand is that developers will get nice intellisense with the methods defined in IProductsController interface.

controller_intellisence_steps

Developing Controllers – ProductsController

In this part we at going to see how we can create AngularJS Controllers for the Product. This controller will use the ProductsModel that we created in the earlier article and also the product service. The products controller will not initialize the product service but an instance will be passed using AngularJS dependency injection. So lets start with ProductsController

When we develop AngularJS application we usually use the $scope for declaring methods, properties etc. As $scope dynamically creates properties and methods at run-time you will notice the errors only at the run-time. To avoid this discrepancy if you look at the AngularJS definition file for TypeScript you will find a interface called ng.IScope, this interface has the base for AngularJS $scope. If you look further in to the definition file you will notice that $rootScope is ng.RootScopeService and ng.IScope extends ng.IRootScopeService.

The following is the class diagram of the classes and interfaces involved and a short note below provides a short description about it

ControllerDiagram

Now lets see how we can use the ng.IScope for Products Controller class. I am going to create a Interface named IProductsController and this interface will extend ng.IScope. The interface definition will belike this

export interface IProductsController&lt;T extends Models.Products.Products&gt;
extends ng.IScope

In the IProductsController interface I have defined the following methods and properties.

Name Type Description
Title: string Property Gets or sets value indicating the name of the controller
Products: Array Property Gets or sets value indicating the the array of products.
IsReading: boolean Property Gets or sets value indicating whether the Products array is getting retrieved from products service or not.
IsSaving: boolean Property Gets or sets value indicating whether the items in the Products array is getting saved using products service or not.
IsSaveSuccess: boolean Property Denotes the flag indicating whether the success or failure of a call to any ProductService operation.
ReadItems:() Method Method used to read products list from product service.
SaveItem: (T:Product) Method Method used to save an individual item in the products list using Product Service.
SaveChanges: () Method Method used to save the Products array that are modified using ProductsService.
DeleteItem: (T:Product) Method Method used to delete a specific product from the Products array using ProductService.
AddItem: (T:Product) Method Method used to add a new product to the Products array using ProductService.
This is a sample code and some methods and properties might be contradictory.

The IProdcutController interface full definition with methods and properties is given below

export interface IProductsController&lt;T extends Models.Products.Products&gt; extends ng.IScope
{
    Title: string;
    ShowImage: boolean;
    Products: Array&lt;T&gt;;
    Items: Array&lt;T&gt;;
    ReadItems: () =&gt; void;
    SaveItem: (T) =&gt; void;
    SaveChanges: () =&gt; void;
    DeleteItem: (T) =&gt; void;
    AddItem: (T) =&gt; void;
    IsReading: boolean;
    IsSaving: boolean;
    IsSaveSuccess: boolean;
}

Now lets see the implementation for ProductsController, the important one to understand here is the constructor, I have highlighted the constructor parameter in bold that indicates the instance of the IProductsController that will be passed while creating a instance of the ProductController in App.ts class. I will explain about it more in detail on the next part.

export class ProductsController&lt;T extends Models.Products.Products&gt;{
    static $inject = [&quot;$scope&quot;, &quot;productService&quot;];
    private _title:string = &quot;&quot;;
    private _showImage:boolean;
    private _products: Array&lt;T&gt;;
    private _service: app.Service.Products.ProductService;

    constructor(public $scope: IProductsController&lt;T&gt;, public productService: app.Service.Products.ProductService){
        this._service = productService;
        this.SetStatus(false, false);
        $scope.ReadItems = () =&gt; { this.ReadAllProducts(); };
        $scope.SaveItem = (T) =&gt; { this.SaveProduct(T); };
        $scope.SaveChanges = () =&gt; { this.SaveProducts(); };
        $scope.AddItem = (T) =&gt; {this.AddProduct(T);};
        $scope.DeleteItem = (T) =&gt; {this.DeleteProduct(T);};
        $scope.Items = new Array&lt;T&gt;();
        $scope.Products = new Array&lt;T&gt;();
        $scope.Title = &quot;ProductsController&quot;;
        $scope.IsSaveSuccess = true;
        $scope.ShowImage = false;
        this.ReadAllProducts();
    }

    private ReadAllProducts() : void {
        this.SetStatus(true, false);
        this._service.Repository.GetAll().then((productCollection)=&gt;{
        this.$scope.Items = productCollection as Array&lt;T&gt;;
        this.$scope.Products = productCollection as Array&lt;T&gt;;
        this.$scope.IsReading = false;
        });
    }

    private SaveProduct(itemToSave: T) : void {
        this.SetStatus(false, true);
        this.$scope.IsSaveSuccess = false;
        this._service.Repository.SaveItem(itemToSave).then((resultFlag)=&gt; { this.$scope.IsSaveSuccess = resultFlag; });
        this.SetStatus(false, false);
    }

    private SaveProducts() : void {
        this.SetStatus(false, true);
        this.$scope.IsSaveSuccess = false;
        this._service.Repository.SaveItems(this.$scope.Items).then((resultFlag)=&gt; { this.$scope.IsSaveSuccess = resultFlag; });
        this.SetStatus(false, this.$scope.IsSaveSuccess);
    }

    private AddProduct(itemToAdd: T): void{
        this.SetStatus(false, true);
        this.$scope.IsSaveSuccess = false;
        this._service.Repository.AddItem(itemToAdd).then((resultFlag)=&gt; { this.$scope.IsSaveSuccess = resultFlag; });
    }

    private DeleteProduct(itemToDelete: T){
        this.SetStatus(false, true);
        this.$scope.IsSaveSuccess = false;
        this._service.Repository.DeleteItem(itemToDelete).then((resultFlag)=&gt; { this.$scope.IsSaveSuccess = resultFlag; });
    }

    private SetStatus(isReading: boolean, IsSaving: boolean){
        this.$scope.IsReading = isReading;
        this.$scope.IsSaving = IsSaving;
    }
}

Adventure with Typescript and AngularJS

Typescript was introduced on 2012 and I was working on it from 2013 since then I was been a biggest admirer of it and have developed numerous HTML applications with TypeScript. In this blog I am not going to touch on fundamentals but a little more advanced topic. One an find the Type Script fundamentals here.

In the coming blogs, I am going to explain how we can create MVC using TypeScript and how we can able to use it in out HTML pages along with AngularJS. Most of plumbing I have done using AngularJS services

I am going to split up the blog in to sub sections as follows

I have used Visual Studio Code for development but you can also use TypeScript playground for generating JavaScript as well with the sample code attached with the blog. Developing applications with TypeScript using VSCode can be found @TypeScript Programming with Visual Studio Code.

So let’s start ……..

Developing Model using Typescript

So now lets create a Model class using TypeScript. I am going to create a Products class and going to have some properties to it. This will used in the controller to bind the values retrieved from service and display it in HTML page. The following class diagram depicts the methods and properties of the Products class and the TypeScritp code is given below.

ModelDiagram

module app.Models.Products{
    export class Products{
        private _productId: number = 0;
        private _productName: string = "";
        private _productCode: string = "";
        private _releaseDate: Date = new Date(2016, 3, 25);
        private _productDescription: string;
        private _price: number;
        private _imageUrl:string;
        private _productCategory:string;

        constructor(id: number, name: string,
        code: string, releaseDate: Date,
        description: string, price: number,
        imageUrl: string, category: string){
            this._productId = id;
            this._productName = name;
            this._productCode = code;
            this._releaseDate = releaseDate;
            this._productDescription = description;
            this._price = price;
            this._imageUrl = imageUrl;
            this._productCategory = category;
        }

        public get Price(): number
        {
            return this._price;
        }

        public set Price(value: number)
        {
             this._price = value;
        }

        public get ProductId(): number
        {
            return this._productId;
        }

        public set ProductId(value: number)
        {
             this._productId = value;
        }

        public get ProductName(): string
        {
            return this._productName;
        }

        public set ProductName(value: string)
        {
             this._productName = value;
        }

        public get ProductCode(): string
        {
            return this._productCode;
        }

        public set ProductCode(value: string)
        {
             this._productCode = value;
        }

        public get Description(): string
        {
            return this._productDescription;
        }

        public set Description(value: string)
        {
             this._productDescription = value;
        }

        public get ReleaseDate(): Date
        {
            return this._releaseDate;
        }

        public set ReleaseDate(value: Date)
        {
             this._releaseDate = value;
        }

        public get ImageUrl(): string
        {
            return this._imageUrl;
        }

        public set ImageUrl(value: string)
        {
             this._imageUrl = value;
        }

        public get ProductCategory(): string
        {
            return this._productCategory;
        }

        public set ProductCategory(value: string)
        {
             this._productCategory = value;
        }

    }
}