In this tutorial, we’re going to build a very simple Windows Store application that uses jQuery and Knockout to get some data from the internet and show this in a GridView
. I’ll show you how you create a new project, get all the TypeScript definitions you need, get data from a web service and bind that to the GridView
control. I’m assuming you have at least a little TypeScript knowledge. If you don’t, you should have a look at the tutorials on http://TypeScriptLang.org first.
File – New
Start by creating a new project using the template Store apps with TypeScript project template I wrote about recently. After this is installed, you can go to the Windows Store section in the TypeScript category in the New Project dialog. Select the Blank App template and give the app a name. I named mine ColourLovers
. Hit OK to create the project.
This will give us an application similar to a blank application created using the JavaScript template, only with TypeScript in place.
Because this application is going to need jQuery and Knockout, we’ll have to get that into the solution. I always use NuGet to get libraries like this into my projects. The easiest way to do this is to open the Package Manager Console from Tools –> Library Package Manager in the menu. In this console window, type:
Install-Package jQuery
to get jQuery. And...
Install-Package knockoutjs
...to install Knockout.
While we’re here, let’s install the TypeScript definition for Knockout too. The definition for jQuery is already included in the project template. Just type...
Install-Package knockout.TypeScript.DefinitelyTyped
...in the package manager console window to get the definition. Note that you can use the Tab key to get completion of the words.
DefinitelyTyped is a huge open source library of TypeScript definitions of JavaScript frameworks. If you would like to use a JavaScript framework in your TypeScript website or application, you should check DefinitelyTyped to see if it contains the TypeScript definition. It would make your life developing your app a lot easier.
Getting Data
To get some data into the app, we’re going to make an Ajax call to the API of Colourlovers
. This API gives us some simple data to work with. To get the data, I would like to use what I always use to make Ajax calls, jQuery.
To get some code completion and syntax checking on jQuery, you’ll have to add a reference to the jQuery.d.ts file that’s in your project. Adding this is easy, just drag the .d.ts file from your solution window to the top of the default.ts file. This will result in a comment like this:
To get the data using jQuery, we are going to use its getJSON function. This function calls the specified URL and when it’s done, it calls the success
function you provided. The result of the Ajax call is passed to the success function.
Inside the then
function after the processAll
, we are going to place the getJSON
function to get the data from ColourLovers.
args.setPromise(WinJS.UI.processAll().then(() => {
$.getJSON("http://www.colourlovers.com/api/patterns/top?format=json",
(result) => {
});
}));
This piece of code looks pretty much the same as it would when writing it in plain old JavaScript. Except for the lambdas, where function
used to be.
Let’s add a little code to the view, our HTML file.
<div id="content"></div>
At this point, we should be able to loop through the result and add some HTML with values from the result to the content
div.
Since we are using TypeScript, it would be nice to have some actual type checking and even code completion. To do this, we’ll make an interface
describing the result from the Ajax call. An interface in TypeScript contains the description of an object. In this case, the returned object is not complex. The entire interface
looks like this:
declare module ColourLovers {
export interface Top {
id: number;
title: string;
userName: string;
numViews: number;
numVotes: number;
numComments: number;
numHearts: number;
rank: number;
dateCreated: string;
colors: string[];
description: string;
url: string;
imageUrl: string;
badgeUrl: string;
apiUrl: string;
}
}
I personally hate to write code like this. Why? Because it’s very easy to have code like this generated by a computer. So I decided to build a website that does exactly that. Converting a JSON object to a TypeScript interface. At http://json2ts.com, you can paste a piece of JSON into the textbox
and have it converted to TypeScript. You can even enter the URL to service that returns JSON and have that converted.
To have the result use the interface
we just created, add it to the callback function. Now, when we just loop though the items returned from ColourLovers
, we can build some UI.
(result: ColourLovers.Top[]) => {
var content = $("#content");
for (var r in result) {
div.append("<h3>" + result[r].title + "<h3>");
div.append("<img src="" + result[r].imageUrl + "" width="150">");
content.append(div);
}
}
Note that when you type inside the callback, you get intellisense on the result.
When you run this app, it should look something like below. Although this app is getting data and showing it on screen, it isn’t exactly what you would expect from a Windows Store app. It would be nice to have some interaction too. You could use jQuery to get some interaction with your app, but there are other ways. Like KnockoutJS, for example.
Binding to the UI
KnockoutJS uses a viewmodel
that is bound to elements in the DOM. If you haven’t used it, please have a look at http://knockoutjs.com/. The site has some very nice tutorials on getting started with using KnockOut in your web applications. It uses data-bind
attributes on HTML elements to bind properties on the viewmodel
to attributes or events in the DOM. It does all change and dependency tracking for you. KnockOut can also be used to render templates.
If you haven’t heard from Knockout before but have build Windows Store apps, this should sound familiar.
Let’s start by creating the viewmodel
. The viewmodel is basically just another TypeScript class. For the sake of simplicity, I added it to Default
module that’s already in the project. I named the class ViewModel
. I added a constructor too, because that’s where we’re going to move the Ajax call we created earlier.
class ViewModel {
constructor() {
}
}
The viewmodel
is going to need one property to use in the DOM. Well, an array to be more specific. This array needs to be an observableArray
. KnockOut uses this function (and a couple more, like a regular observable) to track changes. Whenever you push something into an observableArray
, the UI is updated. The TypeScript version of the observableArray
is generic and takes the type you want to store in the observableArray
. In the case of this tutorial, we’re going to use the interface
we created earlier, Colourlover.Top
.
Just add this line to the ViewModel
class:
top = ko.observableArray<ColourLovers.Top>();
Filling this array is as simple as passing a value to a function. And that’s something you should always keep in mind when working with knockout. You don’t just assign a value to a variable, you pass it to the variable by calling it as a function and passing the new value.
To fill the observableArray
, I moved the ajax call from earlier to the constructor of the ViewModel
and changed the success part as follows:
$.getJSON("http://www.colourlovers.com/api/patterns/top?format=json",
(result: ColourLovers.Top[]) => {
this.top(result);
});
We’ll have to make a last small modification to the TypeScript code before we can move to the HTML part of this chapter. We have to create a new instance of the ViewModel
class and the knockout to do its magic with it by passing it to the applyBindings
function.
At the place where we just removed the Ajax call, we’re going to change the code to this:
args.setPromise(WinJS.UI.processAll().then(() => {
ko.applyBindings(new ViewModel());
}));
Now that the ViewModel
is set up, it is time to have a look at the view, the HTML. In the last chapter, we added some simple HTML to the DOM, but why not use a WinJS control this time, like a ListView
. This way, we get the Windows 8 grid we are used to see. The HTML for a ListView
with GridLayout
looks like this:
<div data-win-control="WinJS.UI.ListView"
style="height:100%"
id="listview"
data-win-options="{layout:{type:WinJS.UI.GridLayout}}">
</div>
At this point, the grid doesn’t display any data. Normally, you would add an option to the data-win-options to set the data source. But since we are using KnockOut, I would like to use the KnockOut data-bind method to set the data source. Unfortunately, this doesn’t work out of the box. There is no data source handler in KnockOut to set the data source of a Windows 8 control. So I’ve created them myself. You can find them over at GitHub. The project contains only two handlers at the moment, but will grow over time. Just add the two handlers to your project and you are ready to go.
Now we can specify the data source with the data-bind
attribute and set it to the top
property of the ViewModel
.
Which results in:
<div data-win-control="WinJS.UI.ListView"
data-bind="datasource:top"
style="height:100%"
id="listview"
data-win-options="{layout:{type:WinJS.UI.GridLayout}}">
</div>
Normally, when you use the ListView
, you would like to specify a template which describes the way your data should be rendered. KnockOut provides its own template engine. You could specify the default template using the data-win-options
attribute, but you’ll lose the reference to KnockOut that way. On my GitHub project, you’ll find the handler to use a KnockOut template. The template itself is specified as follows:
<script id="itemTemplate" type="text/html">
<div >
<div style="width:260px;height:190px"
data-bind="style:{backgroundImage: 'url('+$data.imageUrl+')'}">
<div data-bind="text:title"></div>
</div>
</div>
</script>
You have to add a script like this to the Head
section of the HTML document. This will create a tile of 260px by 190px with its background image set to one from the data returned by the ColourLovers
API. On top of that, the title of the pattern is displayed. Nothing Store app or TypeScript specific about that, just regular KnockOut.
To tell the grid to use this template, change the HTML of the ListView
control to:
<div data-win-control="WinJS.UI.ListView"
data-bind="datasource:top, template:itemTemplate"
style="height:100%"
id="listview"
data-win-options="{layout:{type:WinJS.UI.GridLayout}}">
</div>
The last thing I want to address is that you can use some KnockOut functionality out of the box. Like handling events, even ListView
specific events.
Let's say you would like to handle the clicking/tapping on an item of the grid. You would use the iteminvoked
to do that. Just use the default KnockOut syntax to handle the event.
<div data-win-control="WinJS.UI.ListView"
data-bind="datasource:top, template:itemTemplate, event:{iteminvoked:selectionChanged}"
style="height:100%"
id="listview"
data-win-options="{layout:{type:WinJS.UI.GridLayout}}">
</div>
Of course, you have to add the handler for the event too. Which is nothing more than a function on the ViewModel
.
selectionChanged = (eventArgs) => {
};
That’s It!
You probably thought that creating a Windows Store application that uses TypeScript, jQuery and Knockout would be far more complicated that this. :) By using NuGet and the definitions found at DefinitelyTyped
, you get intellisense and type checking without much effort.
A few last tips to wrap things up:
CodeProject