Abstract: We take a look at how to use TypeScript’s definitions for KnockoutJS to build a small ASP.NET MVC application. Along the way we explore the TypeScript language and gauge how it can be potentially used for build ASP.NET MVC applications that lean on the client side JS Libraries for richness and interactivity

Back in October 1, 2012 when Microsoft Technical Fellow Ander Hejlsberg introduced TypeScript, we had taken a quick look at what is TypeScript and how we could build an MVC 4 template for TypeScript. [That was TypeScript v0.8.x.]

In //BUILD 2013 Anders presented the latest updates to TypeScript as v 0.9.0. Between October 2012 and the present, TypeScript has made steady progress and now includes advanced constructs like Generics and lambda expressions and so on. There has been improvement in the Tooling support as well. Best part has been the community engagement and uptick in TypeScript definition support for majority of JS libraries and frameworks. There is now a Github project called DefinitelyTyped that is maintaining most Type annotations for TypeScript.

So today, we will explore what is takes to use Knockout JS in an app that Uses TypeScript for development of the client side in an ASP.NET MVC 4 application. We will also take a look at the latest tooling support for TypeScript.

Getting Started with TypeScript in Visual Studio 2013 Preview

TypeScript’s tooling support comes in form of an out-of-band extension to Visual Studio that can be downloaded from http://www.microsoft.com/en-us/download/confirmation.aspx?id=34790. The binary, which was at v0.9.1.1 at the time of writing, is approximately a 12 MB in (download) size.

Once downloaded, close Visual Studio and run the installer. In my case, I ran it on Visual Studio 2013 Preview but the installer works for VS 2012 as well.

The installation takes a minute or so to complete, once done, you are good to get started with TypeScript.

Unlike previous tooling, there are no MVC project templates created for TypeScript. The TypeScript installer only installs the ‘HTML Application with TypeScript” project template.”

While we can use the above for demoing TypeScript’s capabilities, we want to see a slightly more practical use for it and that is in an ASP.NET MVC Application.

TypeScript in ASP.NET MVC

Turns out you don’t have to do anything special to include TypeScript in ASP.NET MVC. You start off with the ASP.NET Web Application Project Type.

Next I have selected the MVC template to bring in the nice BootStrap styling etc.

Once the code generation completes, we select the Scripts folder, right click on it and select New Item. In the search window, we type in ‘TypeScript’ to eke out the TypeScript File item and add ‘typescript-list.ts’ file to the project.

Once you click Add, Visual Studio pops up the following dialog for your convenience

This essentially means it has added the build commands required to build .ts files into .js at compile time and if you click Yes, it springs up the Nuget Package Manager dialog.

This is filtered by the tag:typescript thus giving you a list of already available TypeScript definition files. Of the given list, I added jQuery, Knockout, BootStrap and Knockout.Mapping definitions.

Once you click on Close, you’ll end up with a Folder structure for Script as follows

The typings folder has one sub-folder for each library that contains the .ds file for the library’s type definition encapsulated.

Finally we install KnockoutJS using Nuget Package Management Console

PM> install-package knockoutjs

With this, we are all set with the required dependencies, let’s now start with our application.

Note: Installing the Type Definitions does not install the original library. For example installing definitions for KnockoutJS didn’t actually install KO. We had to do that separately.

The Task Listing App in TypeScript

We will start with an easy target that is to create a Task listing app in TypeScript. To make things even simpler, we’ll implement the List or Index page only for the moment and pass some hardcoded values from the controller.

The Task Entity

In the Models folder, we add a Task class with the following definition:

public class TaskDetails

{

public int Id { get; set; }

public string Title { get; set; }

public string Details { get; set; }

public DateTime Starts { get; set; }

public DateTime Ends { get; set; }

}

Build the application.

The Tasks List View

To add a View for the Tasks, we right click on the Views\Home folder and select Scaffold. From the available scaffolding options, we select ‘MVC 5 View – List’ as shown below. This generates the markup for a tabular UI.

In the options of adding the view, we select the Model Class and mark it as a partial view.

Once we click Add, a strongly typed view is scaffolded for us.

Updating the Controller to return dummy data for Tasks

Next we add an Action method that returns some dummy data for us:

public ActionResult Tasks()

{

List<TaskDetails> tasks = new List<TaskDetails>();

for (int i = 0; i < 10; i++)

{

TaskDetails newTask = new TaskDetails

{

Id = i,

Title = "Task " + (i + 1),

Details = "Task Details " + (i + 1),

Starts = DateTime.Now,

Ends = DateTime.Now.AddDays(i + 1)

};

tasks.Add(newTask);

}

return View(tasks);

}



As we can see above, the code return 10 Tasks with some sample data generated on the fly. Running the app and navigating to the /Home/Tasks view, we get the following:

This is our Tasks view rendered on the server side. Lets see what it takes to render it on the client side by building our ViewModel out in TypeScript.

Adding reference to the TypeScript code

In the Tasks.cshtml file, add the following snippet at the bottom of the page

@section Scripts{

<script src="~/Scripts/knockout-2.3.0.js"></script>

<script src="~/Scripts/typescript-list.js"></script>

}

The first script reference adds KnockoutJS to our project. But the second dependency is actually pointing to a JS file that doesn’t really exist. Actually we have typescript-list.ts file instead. Well, the Build task that got added to our Project when we added the first TypeScript file, will ensure that there is a corresponding JS file after a successful build.

Just for confirmation, if you run the application again and navigate to /Home/Tasks; in Visual Studio’s Solution explorer you’ll see a folder structure like the following (note the ts file linked to the generated js file).

Setting up our Knockout ViewModel using TypeScript

With our dependencies in place, lets write our first bit of TypeScript.

Referencing other TypeScript Definitions

First thing to do is reference jQuery and Knockout’s definitions. The syntax for that is as follows:

///<reference path="typings/jquery/jquery.d.ts" />

///<reference path="typings/knockout/knockout.d.ts" />



Next we create a Class called Task Details and declare the properties of the requisite types

class TaskDetails {

id: KnockoutObservable<number>;

title: KnockoutObservable<string>;

details: KnockoutObservable<string>;

starts: KnockoutObservable<string>;

ends: KnockoutObservable<string>;

// … more to come

}

As we can see, we have declared each property as KnockoutObservable with their respective types. The KnockoutObservable<T> generic Type definition is provided via the knockout.d.ts Type description file. Key thing to note here is that we have only defined the variables NOT instantiated them.

To instantiate them, we use the constructor function as per TypeScript syntax as follows:

class TaskDetails

{

// … variable declarations

constructor(id: number, title: string, details: string,

starts: string, ends: string) {

this.id = ko.observable(id);

this.title = ko.observable(title);

this.details = ko.observable(details);

this.starts = ko.observable(starts);

this.ends = ko.observable(ends);

}

}

Note, while instantiating the properties, we are using base KO types here with values passed in to the constructor. Now our View Model contains an array of TaskDetails, so lets setup the ViewModel class.

class TaskViewModel {

public tasks: KnockoutObservableArray<TaskDetails>;

constructor() {

this.tasks = ko.observableArray([]);

}

}

We have declared a TaskViewModel class with one public property task. The type for the property is a KnockoutObservableArray<TaskDetails> that we instantiate in the constructor. Notice how the tasks list is strongly typed so if we try to shove in any random object like we can in JavaScript, we’ll get compile time errors.

Saving Strongly Typed Data as JSON and retrieving it on the Client Side

Traditionally I’ve used an MVC Action Result to return an Empty View and then do an AJAX GET once the document is loaded. This gives us options to load banners, progress bars etc if required. Today I’ll take a different approach and stuff the JSON serialized model data in a Hidden Input field. Then, once the document is loaded, I’ll retrieve it and build a view Model out of it.

To save the data in Hidden Input field, we add the following markup in the Tasks.cshtml

<input type="hidden" id="serverJSON"

value="@Newtonsoft.Json.JsonConvert.SerializeObject(Model)" />

The reason why this works is, as we know, all Razor syntax is evaluated on the server. So the Server uses Newtonsoft Json to serialize the entire Model into JSON and stick it in the Hidden Input field. This method apparently saves one round trip, but if your ViewModel is large, it can result in a rather large page size for initial load.

Now that the data is with us, let’s see how we can use it.

- We first create a serverData object of type any[]. Declaring it as an array gives us minimum Intellisense.

- Next we use the native JSON.parse to convert the string in the serverJSON field to a JS object array. This is the only ‘weakly typed’ object that we have in our TypeScript code. If we were to use Knockout Mapping we could have skipped this step, but we’ll get to KO Mapping another day.

- Next we declare a local variable vm of type TaskViewModel and instantiate it.

- The for loop essentially loops through the data we got from the server and creates strongly typed TaskDetails objects and adds them to the vm.tasks observable array.

- Once the View Model is ready, we use ko.applyBindings to assign the ViewModel to the View.

The complete TypeScript source for this is as follows:

$(document).ready(function () {

var serverData: any[];

serverData = JSON.parse($("#serverJSON").val());

var vm: TaskViewModel;

vm = new TaskViewModel();

var i: number;



for (i = 0; i < serverData.length; i++) {

var serverTask: any;

serverTask = serverData[i];

vm.tasks.push(new TaskDetails(serverTask.Id, serverTask.Title,

serverTask.Details, serverTask.Starts, serverTask.Ends));

}

ko.applyBindings(vm);

});

It is worth stressing here that if we were to try and push any object into the vm.tasks array, we would get an Error as follows:

Updating View to use client side bindings

We remove the entire server side markup and replace it with the following:

<table class="table">

<tr>

<th>Title</th>

<th>Details</th>

<th>Starts</th>

<th>Ends</th>

<th></th>

</tr>

<tbody data-bind="foreach: tasks">

<tr>

<td data-bind="text: title"></td>

<td data-bind="text: details"></td>

<td data-bind="text: starts"></td>

<td data-bind="text: ends"></td>

<td></td>

</tr>

</tbody>

</table>

This is standard KO binding and there is nothing new to it. If we run the application again now, we should get the following view at /Home/Tasks

Our dates look a little ugly because of the default date to string conversion. We can clean that up with help of moment.js. (On a side note, read about Using jQuery and Moment.js in ASP.NET MVC to do Custom Unobtrusive Date Comparison and Validation).

So we add the Moment JS using Nuget. Note we could potentially add Moment’s TypeScript definitions as well, if we were going to do more complex operations. Since we are going to use it for formatting only, I’ll use Moment directly.

Back in the TaskDetails class, we update the constructor to use Moment as follows:

constructor(id: number, title: string, details: string,

starts: string, ends: string) {

this.id = ko.observable(id);

this.title = ko.observable(title);

this.details = ko.observable(details);

this.starts = ko.observable(moment(starts).format("MMM DD, YYYY h:mm:ss a"));

this.ends = ko.observable(moment(ends).format("MMM DD, YYYY h:mm:ss a"));

}



Now if we run the application, we’ll see our view comes up nicely:

Summarizing our TypeScript code

Before we can conclude the article, let’s see what was the JavaScript that our TypeScript code compiled down to:

At runtime we opened the typescript-list.js file and we got the script above. As we can see, this is very close to what we would have written if we were writing the ViewModel ourselves. However I must admit it was much easier to think in terms of a ‘TaskDetails’ entity class and a ‘TaskViewModel’ especially if you are coming from a statically typed language like C# or Java to a more dynamic language like JavaScript. TypeScript provides a nice and easy bridge.

Conclusion

To conclude, we saw the following features of TypeScript in action

- Statically typed Classes

- Generic types

- Typed properties

- Knockout’s TypeScript descriptions

The key reasons for using TypeScript is that it offers better structuring of code while building large-scale JavaScript applications. I must admit that it was easier for me to think in terms of classes than functions which resulted in a clean implementation straight off the bat. However we have barely scratched the surface of TypeScript. In future we’ll look at building much larger applications using TypeScript and leverage more language features like Lambda expressions, Modules etc.

Download the entire source code of this article (Github)

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!