TypeScripted Knockout in ASP.NET MVC

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

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.

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:

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.

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:

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:

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.

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

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.

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:

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.

Sumit is a .NET consultant and has been working on Microsoft Technologies since his college days. He edits, he codes and he manages content when at work. C# is his first love, but he is often seen flirting with Java and Objective C. You can follow him on twitter at @sumitkm or email him at sumitkm [at] gmail

Feedback - Leave us some adulation, criticism and everything in between!

I cant able to find MVC5 - view List in Scaffold dialogue box... How can i add it?.. suggestion pls

Comment posted by
Pat Tormey
on Friday, October 25, 2013 5:44 PM

The RTM is VS 2013 is a little different.. Select New Scaffold item. Then the list option for scaffolding.. The dialog lets you select the TasksDetail and the context (Application)

Comment posted by
Pat To
on Friday, October 25, 2013 6:02 PM

Note: TS complied on Build but I did not see the resulting JS file until I showed all files in VS 2013

Comment posted by
Pat Tormey
on Friday, October 25, 2013 6:54 PM

Note:If you don't use moment typing you'll see a red underline indicating that moment isn't defined. This article actual shows that moment is referenced, but the download code from github does not reference it..

Comment posted by
Trong Phan
on Tuesday, February 18, 2014 12:20 PM

The source code seem not contain all things you describe in the article.
Can you have the one with ko.mapping stuff.

Thanks,

Comment posted by
jitendra
on Tuesday, May 27, 2014 1:10 AM

Hi
can you help me i h ave download your project code but when i am running in my local p.c so typeScript is not working so please let me know what i d
please please please very urgent

Comment posted by
T
on Tuesday, October 28, 2014 10:25 PM

It would be very helpful to make the steps above work. If you follow it word for word, it just doesn't work. Maybe versions have changed things, but as of today, this is not functional, so I'm off to find steps that do work. :-/