If you are a web developer active on the social media and have read about the latest web trends, then you don’t need an introduction to AngularJS.
It is currently one of the hottest JavaScript frameworks for building Single Page Applications (SPA).
Editorial Note: The latest version of Angular is Angular 4. This article uses the first version of Angular called AngularJS which is still very widely used in projects.
AngularJS started catching the attention of many developers around the world because of its strong emphasis on code quality and testing and the ease with which one can get started with it and quickly build single page applications.
AngularJS contains everything that one needs to build a full-fledged JavaScript based application, along with promoting good client-side coding practices.
This article is published from the DotNetCurry .NET Magazine – A Free High Quality Digital Magazine for .NET professionals published once every two months. Subscribe to this eMagazine for Free and get access to hundreds of free tutorials from experts
Getting Familiar with AngularJS and TypeScript
In the 10th edition of DNC magazine, Sumit Maitra posted an excellent article on building an app using Angular JS and ASP.NET MVC; you can take a look at it if you need an introduction to AngularJS.
To learn more about AngularJS, click here Angular Tutorials.
TypeScript is a language created by Microsoft, which gets compiled into JavaScript. As the name itself suggests, TypeScript brings type checking capabilities into JavaScript.
Since most of us are C# developers, TypeScript looks much like a combination of JavaScript and C#. TypeScript has most of the features of Object Oriented languages like C# and Java.
The language designers didn’t try to invent anything, so one doesn’t need much time to get started with TypeScript.
To get started with typescript, here's an awesome tutorial TypeScript Tutorial for Beginners.
TypeScript comes with a set of primitive types:
- number: to represent numeric values
- string: to represent string values
- boolean: to represent Boolean values
- any: to represent any type of value, to be used only when there are multiple possibilities
To create custom types, we need to define classes or interfaces depending on your applications need. Types can be inherited to create child types. Type inheritance in TypeScript is compiled into prototypal inheritance in JavaScript.
A simple TypeScript class looks like the following:
class Square {
private sideLength: number;
constructor(sideLength: number) {
this.sideLength = sideLength;
}
public findArea(): number {
return this.sideLength * this.sideLength;
}
}
The compiled JavaScript of the above class is a self-executing function that returns a JavaScript constructor function, that takes one argument. The above class compiles to:
var Square = (function () {
function Square(sideLength) {
this.sideLength = sideLength;
}
Square.prototype.findArea = function () {
return this.sideLength * this.sideLength;
};
return Square;
})();
As we saw, we need to specify types for every field and method in TypeScript. This may cause a question in your mind on possibility of using existing JavaScript libraries in TypeScript. Luckily, we don’t need to rewrite the libraries in TypeScript, we just need to have TypeScript declaration file for the library available. The type declaration file doesn’t define anything; it just holds declarations of all objects that the library exposes, of which most of them are interfaces.
Visual Studio 2013 provides rich editing support for TypeScript. The file gets compiled and corresponding JavaScript file is generated as soon as the source file is saved. We also get a nice split view to see the TypeScript and JavaScript equivalent side-by-side.

If you need some more inputs on TypeScript, check out Hello TypeScript – Getting Started
Building the OneStopTechVideos Sample App using AngularJS and TypeScript
Now that we got some background on TypeScript and AngularJS, let’s discuss about using TypeScript to write an AngularJS application. Let’s set up a project in Visual Studio 2013 to start creating the application. Open Visual Studio and create a new Empty Web Project named OneStopTechVids. As the name suggests, the application is used to maintain list of training programs offered by a Video-based virtual training company. To the project, add the following NuGet packages:
- AngularJS.Core
- AngularJS.Route
- Bootstrap
- AngularJS.TypeScript.DefinitelyTyped
The fourth package mentioned in the above list is the type declaration file for AngularJS.
Creating an ASP.NET Web API service to serve data
As the data resides on the server, let’s create an ASP.NET Web API service to serve data to the application. Since the focus of the article is to use AngularJS and TypeScript to build SPA’s, I am going to store the data in the memory in form of static collections. Let’s create two simple classes first: TechVideo and Category to represent structure of the data.
public class TechVideo
{
public int Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public int Category { get; set; }
public string Description { get; set; }
public int Rating { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
In a separate class, let’s fill in some sample data that has to be used in the SPA:
public class TechVideosData
{
public static List< techvideo >TechVideos;
public static List< category > Categories;
static TechVideosData()
{
Categories=new List< category >()
{
new Category(){Id=1, Name="JavaScript"},
new Category(){Id=2,Name="ASP.NET"},
new Category(){Id=3,Name="C#"},
new Category(){Id=4,Name="HTML"},
new Category(){Id=5,Name="CSS"},
new Category(){Id=6,Name="Patterns
and Practices"}
};
TechVideos=new List< techvideo >()
{
New TechVideo(){Id=1, Title = "JavaScript
Patterns",Author="Ravi", Category=1,
Description="Takes a close look at most of the
common patterns in JavaScript", Rating=4},
new TechVideo(){Id=2, Title =
"AngularJSFundamentals",Author="Suprotim",
Category=1, Description="Teaches basics of
Angular JS. Introduces the framework and
dives into the concepts around.", Rating=4},
// More test data
};
}
}
We have two simple API services to perform operations on the above data. They are as follows:
public class CategoriesController : ApiController
{
// GET api/< controller >
public IEnumerable< category > Get()
{
return TechVideosData.Categories;
}
}
public class TechVideosController : ApiController
{
// GET api/< controller >
public IHttpActionResult Get()
{
var videos = TechVideosData.TechVideos;
return Ok(videos);
}
// GET api/< controller >/5
public IHttpActionResult Get(string title)
{
var video = TechVideosData.TechVideos.FirstOrDefault(tv => tv.Title.Equals(title, StringComparison.InvariantCultureIgnoreCase));
if (video != null)
{
return Ok(false);
}
else
{
return Ok(true);
}
}
// POST api/< controller >
public IHttpActionResult Post(
[FromBody]
TechVideo value)
{
var maxId = TechVideosData.TechVideos.Max(vid => vid.Id);
value.Id = maxId + 1;
TechVideosData.TechVideos.Add(value);
return Ok(value);
}
// PUT api/< controller >/5
public IHttpActionResult Put(int id, [FromBody]
TechVideo value)
{
for (int counter = 0; counter < TechVideosData.TechVideos.Count; counter++)
{
if (TechVideosData.TechVideos[counter].Id == id)
{
TechVideosData.TechVideos[counter] = value;
return Ok();
}
}
return NotFound();
}
public IHttpActionResult Patch(int id, [FromBody]
TechVideo value)
{
for (int counter = 0; counter < TechVideosData.TechVideos.Count; counter++)
{
if (TechVideosData.TechVideos[counter].Id == id)
{
TechVideosData.TechVideos[counter].Rating = value.Rating;
return Ok();
}
}
return NotFound();
}
// DELETE api/< controller >/5
public IHttpActionResult Delete(int id)
{
for (int counter = 0; counter < TechVideosData.TechVideos.Count; counter++)
{
if (TechVideosData.TechVideos[counter].Id == id)
{
TechVideosData.TechVideos.RemoveAt(counter);
return Ok();
}
}
return NotFound();
}
}
Building the Single Page Application (SPA)
Creating Angular module and configuring Routes:
The sample app that we are going to create in this walkthrough has three pages: List videos, Add a video and Edit a video. I am not going to cover the Edit video view here, but the code is made available in the downloadable file at the end of this article. I am leaving it to the readers to read the code and understand the functionality of the page.
To start with, add a new TypeScript file to the project and add references to Angular and Angular route to the file.
/// ///
Delete all the default code in the file and create a module. A module in TypeScript is similar to a namespace in C#. It can hold definitions of a number of types. While compiling to JavaScript as a function, you can also add some logic directly to the module, but amount of logic should be minimized.
module OneStopTechVidsApp { }
First thing that we add to any Angular JS application is creating a module and configuring routes. Statement for creating module remains the same in TypeScript as in plain JavaScript.
var app = angular.module("techVidsApp", ['ngRoute']);
Let’s try to understand the way a configuration block is created in JavaScript:
app.config(function (dependency) {
//logic
});
The config block expects an executable function to be passed inside it. This function is going to be called immediately and it is not going to be instantiated. In the context of TypeScript, the function can be defined as one of the following:
- A class with a constructor and with no other functional components
- It can even be a class with a static function and the static function would be invoked while registering the config block
Let’s use the first approach to define the config. We will use the second approach later for another component. The config block needs $routeProvider for registering routes of the application. We can use the config.$inject to inject the dependency or, specify the dependencies in array format while registering the component. Following is our config block:
export class Config {
constructor($routeProvider: ng.route.IRouteProvider) {
$routeProvider.when("/list", {
templateUrl: "App/Templates/VideoList.html",
controller: "TechVidsListCtrl"
})
.when("/list/:id", {
templateUrl: "App/Templates/VideoList.html",
controller: "TechVidsListCtrl"
})
.when("/add", {
templateUrl: "App/Templates/AddVideo.html",
controller: "AddTechVideoCtrl"
})
.when("/edit/:id", {
templateUrl: "App/Templates/EditVideo.html",
controller: "EditTechVideoCtrl"
})
.otherwise({
redirectTo: '/list'
});
}
}
Config.$inject = ['$routeProvider'];
app.config(Config);
Factory to interact with Web API:
Let’s create a factory with a number of asynchronous operations to talk to either Web API or to the local data cache. A factory is a function that returns an object. In general, JavaScript implementation of a factory looks like the following:
app.factory(‘name’, function (dependencies) {
//Logic
return {
field1: value1,
method1: function1,
//Other members to be returned
};
});
Simulating the exact same behaviour in TypeScript is a bit challenging. Let’s rephrase the factory as follows to make it easier to create it in the form of a class:
app.factory(‘name’, function (dependencies) {
function FactoryType {
this.field1 = < somevalue > ;
this.method1 = function () {
//Logic
};
//Other members of the FactoryType
}
return new FactoryType();
});
The object of the type FactoryType would look the same as the object returned in the first case; but it is created in a different way.
In the TypeScript class, we can create a static method that returns an object of the same class and registers the static method as a type. A skeleton of it looks like the following:
class MyClass {
constructor() {
//Logic of constructor
}
method1(): return -type { //Logic in the method
};
public static MyClassFactory() {
return new MyClass();
}
}
app.factory(‘myFactory’, MyClass.MyClassFactory);
Since our factory is going to talk to Web API endpoints, we need the dependencies of $http and $q in it. Also, as we will be dealing with custom objects for Video and Category, let’s create simple classes to hold the properties that we need in these objects. I prefer creating a separate module for creating the custom types, this keeps the declarations and the definitions separated. Following is a module with Video and Category classes:
module Extensions {
export class Video {
id: number;
title: string;
description: string;
author: string;
rating: number;
category: number;
}
export class Category {
id: number;
name: string;
}
}
In the factory class, we will have a set of private fields that have to be available for all the methods. We will set values to these fields in either constructor or in the methods. Following is the factory class with the required private fields, constructor and the static factory method:
export class TechVidsDataSvc {
private videos: Array < Extensions.Video > ;
private categories: Array < Extensions.Category > ;
private techVidsApiPath: string;
private categoriesApiPath: string;
private httpService: ng.IHttpService;
private qService: ng.IQService;
constructor($http: ng.IHttpService, $q: ng.IQService) {
this.techVidsApiPath = "api/techVideos";
this.categoriesApiPath = "api/categories";
this.httpService = $http;
this.qService = $q;
}
public static TechVidsDataSvcFactory($http: ng.IHttpService,
$q: ng.IQService): TechVidsDataSvc {
return new TechVidsDataSvc($http, $q);
}
}
All methods in the factory would be asynchronous and return promises. The private fields, videos and categories would be used to cache data locally and use them to serve data to the application whenever needed.
Let’s start adding logic to the factory by adding a method to fetch all videos. This method will make a request to the API service if the videos are not already loaded. Otherwise, it would return the cached data. In both cases, the data would be wrapped inside a promise to make behaviour of the method consistent. When it fetches data from the service, it updates the local cache with the data received. It is good to provide an option to forcefully refresh data from the server when needed; it can be done by accepting a Boolean value to this method. Following snippet shows the implementation:
getAllVideos(fetchFromService ? : boolean): ng.IPromise < any > {
var self = this;
if (fetchFromService) {
return getVideosFromService();
} else {
if (self.videos !== undefined) {
return
self.qService.when(self.videos);
} else {
return getVideosFromService();
}
}
function getVideosFromService(): ng.IPromise < any > {
var deferred = self.qService.defer();
self.httpService.get(self.techVidsApiPath).then(function (result: any) {
self.videos = result.data;
deferred.resolve(self.videos);
}, function (error) {
deferred.reject(error);
});
return deferred.promise;
}
}
As you see, I created a function inside the method to avoid repeating the code to fetch videos from the API.
To add a video, we need to make an HTTP POST request. Once the API call is successful, the video object is added to the local cache after assigning id of the video received in response to the API call. This is done to keep the local copy consistent with the copy on the server. Following is the method that adds a video.
addVideo(video: Extensions.Video): ng.IPromise < any > {
var self = this;
var deferred = self.qService.defer();
self.httpService.post(self.techVidsApiPath, video)
.then(function (result) {
video.id = result.data.id;
self.videos.push(video);
deferred.resolve();
}, function (error) {
deferred.reject(error);
});
return deferred.promise;
}
Other methods in the service follow a similar pattern. You can take a look at them in the source code.
Creating Main page and Menu
The page we are going to design has a menu on the left side with links to browse videos by categories or add a new video. At the centre, the page would contain the ng-view directive, the place where templates of other pages would be rendered.

Following is the mark-up in the main page:
We need a small Controller to serve data about categories that are used to generate a list of links on the left menu. In Angular, a controller gets instantiated. So, we can simply create a class and register it as a controller, we don’t need to follow any conventions like we did in cases of the factory and the config blocks. But the objects used for data binding have to be made available on the Scope. A general interface type for scopes exists in the Angular type declaration file, but we need to create a child type to accommodate the new objects to be added to the scope specific to the controller.
Add the following interface to the Extensions module created above:
export interface ITechVidsCategoryScope extends ng.IScope {
categories: Array; }
The controller for serving the categories is straight forward. It just makes a call to the method in the service and assigns the obtained results to scope.
export class TechVidsCategoryCtrl {
private $scope: Extensions.ITechVidsCategoryScope;
private dataSvc: TechVidsDataSvc;
private init(): void {
var self = this;
self.dataSvc.getAllCategories().then(function (data) {
self.$scope.categories = data;
});
}
constructor($scope: Extensions.ITechVidsCategoryScope,
techVidsDataSvc: TechVidsDataSvc) {
this.$scope = $scope;
this.dataSvc = techVidsDataSvc;
this.init();
}
}
TechVidsCategoryCtrl.$inject = ['$scope', 'techVidsDataSvc'];
app.controller('TechVidsListCtrl', TechVidsListCtrl);
View to list all videos
Let’s design the View to list the videos. As you see in the above screenshot, the view consists of a list of divs that show details of the videos with an option to change rating of the video and a link for edit/delete. The voting buttons cannot be enabled for any value of rating. The buttons should prevent the user from going below 1 and going above 5. This can be achieved easily using Angular’s data binding. Following is the mark-up in the video list view:
{{video.title}}
by {{video.author}}
{{video.rating}}
This view is created to act in two ways: one is to display all videos and other is to display videos based on the category received in the URL. As we already saw, we need to create a scope type specific to this view.
export interface ITechVidsScope extends ng.IScope {
videos: Array < Video > ;
upRate(id: number, rating: number): void;
downRate(id: number, rating: number): void;
}
The TechVidsListCtrl is responsible to fetch the videos based on route parameter and handle functionality to modify rating of the videos. Following is the implementation:
export class TechVidsListCtrl {
private $scope: Extensions.ITechVidsScope;
private $routeParams: Extensions.ITechVidsRouteParams;
private dataSvc: TechVidsDataSvc;
private init(): void {
var self = this;
//Fetching all videos if id is not found in route path
if (self.$routeParams.id !== undefined) {
self.dataSvc.getVideosByCategory(parseInt(this.$routeParams.id))
.then(function (data) {
self.$scope.videos = data;
});
}
//Fetching videos specific to category if id is found in route path
else {
self.dataSvc.getAllVideos().
then(function (data) {
self.$scope.videos = data;
});
}
}
constructor($scope: Extensions.ITechVidsScope,
$routeParams: Extensions.ITechVidsRouteParams,
dataSvc: TechVidsDataSvc) {
var self = this;
self.$scope = $scope;
self.$routeParams = $routeParams;
self.dataSvc = dataSvc;
self.$scope.upRate = function (id: number, rating: number) {
self.dataSvc.setRating(id, rating + 1)
.then(function () {
self.init();
});
};
self.$scope.downRate = function (id: number, rating: number) {
self.dataSvc.setRating(id, rating - 1)
.then(function () {
self.init();
});
};
self.init();
}
}
TechVidsListCtrl.$inject = ['$scope', '$routeParams', 'techVidsDataSvc'];
View to add a new Video
The add video view is responsible to accept inputs, validate them and post the values to the Web API endpoint. We will use Angular’s data validation features to validate the inputs and display the error messages. The list of validations performed on this page is:
- Video should have a title and the title shouldn’t be already assigned to any of the existing videos (custom validation directive, will be discussed later)
- A category should have been selected
- Author’s name should be entered and it shouldn’t have numbers or special characters
- Video must have a description with at least 50 characters to 200 characters
Mark-up of the page seems heavy because of the validations. Following is the mark-up:
Please enter a title for the video Title already used
Please select a category
Please enter name of the author Author's name cannot contain numbers or special characters
Please enter a description for the video Description should have 50 - 200 characters
Following is the controller for this view:
export class AddVideoCtrl {
$scope: Extensions.IAddTechVidScope;
$window: ng.IWindowService;
dataSvc: TechVidsDataSvc;
constructor($scope: Extensions.IAddTechVidScope,
$window: ng.IWindowService, dataSvc: TechVidsDataSvc) {
var self = this;
self.$scope = $scope;
self.$window = $window;
self.dataSvc = dataSvc;
self.$scope.name = /^[a-zA-Z ]*$/;
self.$scope.addVideo = function () {
self.$scope.video.rating = 4;
self.$scope.video.category = self.$scope.category.id;
dataSvc.addVideo(self.$scope.video)
.then(function () {
var category = self.$scope.video.category;
self.$scope.video = {
id: 0,
title: "",
description: "",
category: 0,
author: "",
rating: 0
};
self.$scope.techVidForm.$setPristine();
self.$window.location.href = "#/list/" + category;
});
};
self.$scope.cancelVideo = function () {
self.$scope.video = newExtensions.Video();
self.$scope.category = null;
self.$scope.techVidForm.$setPristine();
};
self.init();
}
private init(): void {
var self = this;
self.dataSvc.getAllCategories()
.then(function (data) {
self.$scope.categories = data;
});
}
}
AddVideoCtrl.$inject = ['$scope', '$window', 'techVidsDataSvc'];
Directive to validate title
To check if the title assigned to the video is unique, we need to create a custom validation directive. In Angular, a directive is a function that returns a special object that has a set of pre-defined properties. In TypeScript, we can create a static method and make it return the required directive object.
For validation, we need two fields in the custom directive:
- require, to be able to use functionalities of ngModel directive
- link, to perform validation logic
The link function would invoke the $setValidity method of ngModel to set the validity of the input field based on certain condition. Following is the implementation of the directive:
export class UniqueVideoTitle {
public static UniqueVideoTitleDirective(dataSvc: TechVidsDataSvc): ng.IDirective {
return {
require: 'ngModel',
link: function (scope: ng.IScope,
element: ng.IAugmentedJQuery,
attrs: ng.IAttributes, ctrl: ng.INgModelController) {
element.bind('blur', function () {
var viewValue = element.val();
dataSvc.checkIfVideoExists(viewValue)
.then(function (result) {
if (result === "true") {
ctrl.$setValidity("uniqueVideoTitle", true);
} else {
ctrl.$setValidity("uniqueVideoTitle", false);
}
}, function (error) {
ctrl.$setValidity("uniqueVideoTitle", false);
});
});
}
};
}
}
app.directive('uniqueVideoTitle', ['techVidsDataSvc', UniqueVideoTitle.UniqueVideoTitleDirective]);
Conclusion
I think, by now you must have got a good understanding on implementing Angular components using TypeScript. As we saw, TypeScript makes strict type checking on the objects and it doesn’t let the code compile unless it resolves all objects. This makes the life of programmers a lot easier as we don’t have to cross-check the properties referred on the objects that would have otherwise remained unknown till runtime.
Download the entire source code from our GitHub Repository at bit.ly/dncm12-angular
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Rabi Kiran (a.k.a. Ravi Kiran) is a developer working on Microsoft Technologies at Hyderabad. These days, he is spending his time on JavaScript frameworks like AngularJS, latest updates to JavaScript in ES6 and ES7, Web Components, Node.js and also on several Microsoft technologies including ASP.NET 5, SignalR and C#. He is an active
blogger, an author at
SitePoint and at
DotNetCurry. He is rewarded with Microsoft MVP (Visual Studio and Dev Tools) and DZone MVB awards for his contribution to the community