Skip to content

Building Great #WinApps: Your first WinJS app, part 1

by Brandon on January 28th, 2014

Before I dive into the overall architecture behind my existing apps, I thought I’d walk you through how I recommend building a brand new WinJS app.

First of all, I’m going to assume you have Visual Studio 2013. You can get the free Express version here. It includes a few templates for JavaScript Windows Store apps. I don’t find the UI templates useful, but I do make use of the navigator.js helper included in the Navigation App template, so I recommend starting with that.

Our first example app will be a simple UI over an existing REST API which returns JSON. In this case, primarily due to its public availability with no API key requirement, we’re going to use the Internet Chuck Norris Database’s joke API.

This post will go into verbose detail explaining the boilerplate code you get in the Navigation App template, and I’ll point out a few pieces I don’t like and think you should delete. If you’re already familiar with the basics of a WinJS app this may not be the most interesting thing you could be reading. On the other hand, any input on the format, or corrections/additions, are most welcome!

Creating our app project

After starting Visual Studio, select the New Project option from the start page or file menu. You’ll get this dialog where you’ll choose the Navigation App template for a JavaScript / Windows Store app.

image

The result of using this template is that your app is filled out with a bit of boilerplate code and a basic file layout which looks like this:

image

What is all this stuff? Well let’s work top-down:

  1. A reference to the WinJS library. This means you can reference the WinJS JavaScript and CSS files from your project without actually including those files. The Windows Store will make sure the correct version of WinJS is downloaded and installed on the user’s machine when your app is downloaded (chances are it is already there, as most of the in-box apps use it).
  2. default.css, a file which contains some boilerplate CSS that is by default applied to every page in your app.
  3. A few placeholder images for your tile, splash screen, and the store.
  4. default.js which handles app startup and hosts the navigation infrastructure. I’ve always referred to this as the “MasterPage” in my code, though I may try to think of a better name in time for part 2.
  5. navigator.js which is kind of a funny thing. I don’t really know why it isn’t part of WinJS, especially in 2.0 (i.e. Windows 8.1). The actual navigation stack is part of WinJS, under the WinJS.Navigation namespace. What this file provides is a custom UI control (using the WinJS control infrastructure) that combines the WinJS.Navigation navigation stack with the WinJS PageControl infrastructure (which is essentially a mechanism for loading separate HTML files and injecting them into the DOM). I’ll explain this in more detail below.
  6. page/home directory. This directory contains three files which constitute a “page control” in WinJS lingo. This is the only page your MasterPage will host if you were to run this app right now.
  7. default.html — This is paired with default.js and default.css to define the “MasterPage” I described earlier. It’s the main entry point for the app.
  8. package.appxmanifest — The package manifest is an XML file which defines everything about how Windows deploys your app package when the user chooses to install it. It specifies your app’s main entry points (generally an executable or an HTML file), and also defines which permissions (or “capabilities”) your app requires, which app contracts it implements (“declarations”), and how your app should be represented throughout system UI like the Start screen (i.e. its name, tile images, etc). I will of course dive into this in more detail later as well.

So what does all this code do?

If you run this app right now, a few things happen:

  1. Windows starts wwahost.exe, the host process for JavaScript apps.
    -You can think of this process as being a lot like iexplore.exe (the Internet Explorer process) but without any UI (“chrome”) elements, and designed to host true applications instead of for browsing web sites.
  2. wwahost.exe loads the StartPage specified in your manifest, in this case, default.html from your app package.
  3. default.html triggers the loading of core files like default.css and default.js.
  4. The default.js code begins executing as soon as the reference in default.html is hit.

Scoping your code to the current file

Now, most of your JavaScript files are going to follow a pattern you’ll see in default.js. That pattern is:

(function () {
“use strict”;

// Bunch of code

})();

JavaScript developers are likely familiar with this pattern (sometimes called the “module pattern”). There are two things to note here: the “use strict” directive, and the outer function wrapping your code. “use strict” is an ECMAScript 5 feature which tells the JavaScript engine to enforce additional rules which will help you write better code. For example, you will be required to declare variable names before you can use them.

The other piece is that outer function. Without this outer function definition, anything defined in “bunch of code” would be added to the global namespace. This encapsulation technique is widely used by JavaScript developers to scope code to the current file. You can then use methods I’ll describe shortly to expose specific things to broader scopes as needed.

Digging into default.js

When we last left our executing app, it was executing the code from default.js. So then what? Let’s break down the default.js code the template provided.

First you’ll see 5 lines like this:

var activation = Windows.ApplicationModel.Activation;
var app = WinJS.Application;

JavaScript doesn’t have a “using namespace” directive. In fact, it doesn’t necessarily have a concept of namespaces at all out of the box. Instead you have a global namespace with objects hanging off it, but some of the objects serve no purpose other than to segment other objects/properties/methods. In other word, de facto namespaces.

All WinRT APIs are exposed as a set of classes hanging off of of the Windows namespace (such as Windows.ApplicationModel.Activation in the above example). Furthermore, WinJS defines a helper for implementing the common JavaScript equivalent of namespaces, and uses that to expose all of its functionality. To avoid typing out the fully qualified namespaces all the time, commonly used ones can be referenced by defining variables as above.

app.addEventListener(“activated”, function (args) {
    if (args.detail.kind === activation.ActivationKind.launch) {

Here the app registers a handler for the “activated” event. Activation is the word Windows uses to describe entry points for when the user invokes your application from anywhere else in the system. There are many kinds of activation, but the most basic “kind” is called “launch.” This is what happens when your app is started from its tile in Start, or when you hit “Go” in Visual Studio.

if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
    // TODO: This application has been newly launched. Initialize
    // your application here.
} else {
    // TODO: This application has been reactivated from suspension.
    // Restore application state here.
}

Now we find some code that theoretically deals with the application lifecycle. I don’t like this approach, and I suggest deleting all that.

nav.history = app.sessionState.history || {};

This attempts to restore the navigation stack from history data saved before your app was terminated. I don’t like this either, so we’ll delete that too.

nav.history.current.initialPlaceholder = true;

This is telling the navigation stack that the current page shouldn’t contribute to the back stack. I don’t like this here either, so be gone with it!

// Optimize the load of the application and while the splash screen is shown, execute high priority scheduled work.
ui.disableAnimations();
var p = ui.processAll().then(function () {
    return nav.navigate(nav.location || Application.navigator.home, nav.state);
}).then(function () {
    return sched.requestDrain(sched.Priority.aboveNormal + 1);
}).then(function () {
    ui.enableAnimations();
});

args.setPromise(p);

Now things get interesting.

Okay, well, the disable/enable animations thing is an optimization to avoid unnecessary work while the system splash screen is still up. So maybe that’s not that interesting. I actually think it’s a little hokey, but we’ll leave it for now. However…

WinJS.UI.processAll is a very important WinJS function which tells it to process WinJS declarative control bindings in your HTML. In other cases you’d probably specify a root element, but in this case none is specified, so it starts at the root of of the DOM — which means processing the markup from default.html.

Essentially what this does is walk the DOM looking for data-win-control attributes, which specify that an element should host a WinJS control. For each one found, it invokes the associated JavaScript code needed to create the control.

This time, the only control it will find is this one from default.html:

<div id=”contenthost” data-win-control=”Application.PageControlNavigator” data-win-options=”{home: ‘/pages/home/home.html’}”></div>

This invokes code from navigator.js, where Application.PageControlNavigator is defined. It also deserializes the JSON string provided in data-win-options into an object and passes that as the “options” parameter to the Application.PageControlNavigator construction methods, along with a reference to the DOM element itself.

What’s all this .then() stuff?

WinJS.UI.processAll is an async method, and so its return value is a promise object. If you’re familiar with C# async, this is roughly equivalent to Task<T>. However, instead of representing the task itself, the idea is this object represents a promise to return the requested value or complete the requested operation.

The number one thing you can do with a promise object is to specify work to be done when the promise is fulfilled. To do this you use the promise’s .then method.

In this case, we tell processAll to do its thing, which results in instantiating the PageControlNavigator asynchronously. When it’s done, the code in the .then() block executes and we call nav.navigate to navigate to our app’s start page.

When that’s done, this boilerplate code requests that the WinJS scheduler (a helper for prioritizing async handlers and other work executed on the current thread) execute all tasks that we or WinJS have declared as being high priority. That’s another async task, and when it’s completed, we re-enable animations.

The args.setPromise line is really about the system splash screen. During app activation the system keeps the splash screen visible until after your “activated” handler has returned. However, we actually want to keep it up until we’re ready to show something, so the setPromise method lets you specify a promise which the splash screen will wait on. When it’s fulfilled, the splash screen will do its fade animation and your app UI will be shown.

The promise we pass is actually the return value of our last .then() statement after processAll. WinJS’s implementation of promises supports a very handy chaining feature which is relevant here. Every call to .then() returns another promise. If the function you provide as a completion handler to .then() returns a promise, then the promise returned by .then() is fulfilled when that promise is fulfilled.

Hopefully your head didn’t explode there. When first encountered, this can take a minute to wrap your head around, but I swear it makes sense =)

To try and help clarify that, let’s take another look at that part of the code with some of the parameters stripped out and a few numbers labeling the approximate sequence of events:

var p = ui.processAll().then(function () { // 1
    return nav.navigate(); // 3
}).then(function () {
    return sched.requestDrain(); // 4
}).then(function () {
    ui.enableAnimations(); // 5
});

args.setPromise(p); // 2

  1. So our first step is that processAll kicks off an async task and returns a promise.
  2. The very next thing that happens is the args.setPromise call. Then our activated handler runs to completion.
  3. Later on, when the processAll task completes, its promise is fulfilled, and we run the handler that invokes nav.navigate. That call itself returns another promise, which bubbles out to the promise returned by the .then() it handled.
  4. Only after that task is complete, do we run the next handler, which calls requestDrain. Again, this returns its own promise.
  5. When that completes, we’ll run the code to re-enable animations.
  6. When that returns, the whole chain will finally be complete, and “p” will be be fulfilled. Only then will the splash screen dismiss.

Re-read that if you need to. If you haven’t been exposed to promise-based async development before, I can imagine it taking a few minutes to process all that. Once you figure out the promise model, you’re pretty much good to go.

If you want to go read more about promises, some helpful links @grork suggested are:

MSDN / Win8 App Developer Blog: All about promises (for Windows Store apps written in JavaScript)

MSDN: Asynchronous programming in JavaScripts (Windows Store apps)

MSDN Blogs / The Longest Path: WinJS Promise Pitfalls

Got it. What about the rest of default.js?

Our default.js file has just a little more code we should deal with:

app.oncheckpoint = function (args) {
    // TODO: This application is about to be suspended. Save any state
    // that needs to persist across suspensions here. If you need to
    // complete an asynchronous operation before your application is
    // suspended, call args.setPromise().
    app.sessionState.history = nav.history;
};

This is using the “oneventname” shorthand for registering an event handler for the “checkpoint” event. As the template comment suggests, this event indicates the app is about to be suspended, and that it should immediately release any resources it can, and persist any information it may need the next time it’s started, if the system decides to terminate it while suspended.

I’ll cover more on suspension and the app lifecycle later. For now, I suggest deleting the boilerplate code in this handler, but keep the handler itself around as it will be useful later.

Finally, we come to the last bit of default.js code:

app.start();

Up until now, the code in this file has been defining functions but not actually executing them. This line kicks off WinJS’s app start-up infrastructure, which ultimately results in the “activated” handler we described above being invoked, after the rest of the default.html page has been loaded.

Our trimmed down default.js

If you followed my suggested deletions, and also delete the comments inserted by the template, your default.js should now look like this:

(function () {
    “use strict”;

    var activation = Windows.ApplicationModel.Activation;
    var app = WinJS.Application;
    var nav = WinJS.Navigation;
    var sched = WinJS.Utilities.Scheduler;
    var ui = WinJS.UI;

    app.addEventListener(“activated”, function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            ui.disableAnimations();
            var p = ui.processAll().then(function () {
                return nav.navigate(Application.navigator.home);
            }).then(function () {
                return sched.requestDrain(sched.Priority.aboveNormal + 1);
            }).then(function () {
                ui.enableAnimations();
            });

            args.setPromise(p);
        }
    });

    app.oncheckpoint = function (args) {
    };

    app.start();
})();

Okay, I cheated and also removed the “nav.location || “ and “, nav.state” parts of what was being passed to nav.navigate. Since we deleted the code that restored that from sessionState, we don’t need them.

Onto home.js

Now that we’ve gone over the basic bootstrapping done in default.js, we can take a look at our home page. The only interesting part right now is actually home.html.

lt;!DOCTYPE html>
<html>
<head>
<meta charset=”utf-8″ />
<title>homePage</title>

<!– WinJS references –>
<link href=”//Microsoft.WinJS.2.0/css/ui-dark.css” rel=”stylesheet” />
<script src=”//Microsoft.WinJS.2.0/js/base.js”></script>
<script src=”//Microsoft.WinJS.2.0/js/ui.js”></script>

<link href=”/css/default.css” rel=”stylesheet” />
<link href=”/pages/home/home.css” rel=”stylesheet” />
<script src=”/pages/home/home.js”></script>
</head>
<body>
<!– The content that will be loaded and displayed. –>
<div class=”fragment homepage”>
<header aria-label=”Header content” role=”banner”>
            <button data-win-control=”WinJS.UI.BackButton”></button>
<h1 class=”titlearea win-type-ellipsis”>
<span class=”pagetitle”>Welcome to ChuckNorrisJokes!</span>
</h1>
</header>
<section aria-label=”Main content” role=”main”>
<p>Content goes here.</p>
</section>
</div>
</body>
</html>

Again there are some things I think you should delete. They are:

  1. The outer html, body, charset, and <title> tags are just utterly unused. The reasons will become clearer when I get to describing the fragment loader in a later post. In essence this code is dead on arrival and just shouldn’t be here.
  2. The WinJS references are redundant. They’re already loaded by default.html, and serve no purpose here. At best this will be optimized to a no-op, at worst it’s going to run redundant code.
  3. Default.css is the same story. No idea why the template puts this here, even MSDN advises you not to do this exact thing.
  4. The back button. This may seem odd, since I did tell you to choose a Navigation app. The reasons for this will become more clear as we evolve the app template. Suffice to say that having the navigator capability can be useful regardless of whether you actually expose a back button. And it’s nice to have the option to expose later if you want to, or on specific pages where it’s more useful.

When we boil it down to the functional parts, the entire file looks like this:

<link href=”/pages/home/home.css” rel=”stylesheet” />
<script src=”/pages/home/home.js”></script>
<div class=”fragment homepage”>
<header aria-label=”Header content” role=”banner”>
<h1 class=”titlearea win-type-ellipsis”>
<span class=”pagetitle”>Welcome to ChuckNorrisJokes!</span>
</h1>
</header>
<section aria-label=”Main content” role=”main”>
<p>Content goes here.</p>
</section>
</div>

An important thing to remember is that this is not meant to be a complete HTML file. We never intend it to be. It’s a fragment of HTML which will get loaded into the document described in default.html. That’s why that outer code is superfluous. We already did that stuff in default.html.

What’s left should look fairly straightforward. We load the mostly empty JS and CSS associated with this page, and then define a header and body with some placeholder content.

Let’s make this an app!

We’re going to start very simple and build out from there. For this first part of the mini-series, our goal is simply to display a random joke from the Chuck Norris joke database.

To do that, we actually need very little code. Let’s start by changing home.html to provide us a place to render the joke text:

<link href=”/pages/home/home.css” rel=”stylesheet” />
<script src=”/pages/home/home.js”></script>
<div class=”fragment homepage”>
    <header aria-label=”Header content” role=”banner”>
        <h1 class=”titlearea win-type-ellipsis”>
            <span class=”pagetitle”>Chuck Norris joke of the day!</span>
        </h1>
    </header>
    <section aria-label=”Main content” role=”main”>
    <p id=”jokeText”></p>
    </section>
</div>

The only spots I changed are in bold. The first is just a cosmetic change to our header. The latter removes the placeholder text, and assigns an id to the paragraph element so we can reference it later.

Now if we jump over to home.js, you’ll find this:

(function () {
    “use strict”;

    WinJS.UI.Pages.define(“/pages/home/home.html”, {
        // This function is called whenever a user navigates to this page. It
        // populates the page elements with the app’s data.
        ready: function (element, options) {
            // TODO: Initialize the page here.
        }
    });
})();

Again, you can delete the template comments after you’ve read them once. To display our joke we’re going to do three things:

  1. Make a request to the API endpoint at http://api.icndb.com/jokes/random/
  2. Parse the response to find the joke text.
  3. Assign that to the innerText property of our jokeText element.

To make our request we’re going to use the standard JavaScript XmlHttpRequest mechanism, but we’ll call it via the handy WinJS.xhr wrapper. WinJS.xhr is great because it takes a simple property bag of options and gives you back a promise for the result of the request.

When you type WinJS.xhr( into Visual Studio you’ll get a handy IntelliSense description:

image

As the default request type is GET, we only really care about the url field, so that’s the only option we’ll populate.

(function () {
    “use strict”;

    WinJS.UI.Pages.define(“/pages/home/home.html”, {
        ready: function (element, options) {
            var jokeTextElement = element.querySelector(“#jokeText”);
            return WinJS.xhr({
                url: “http://api.icndb.com/jokes/random/”,
            }).then(function (response) {
                // response is the XmlHttpRequest object,
                // ostensibly in the success state.
                try {
                var result = JSON.parse(response.responseText);
                }
                catch (e) {
                debugger;
            }

            if (result && result.value && result.value.joke) {
                jokeTextElement.innerText = result.value.joke;
            }
            else {
                jokeTextElement.innerText = “The server returned invalid data =/”;
            }
        }, function (error) {
                // Error is the XmlHttpRequest object in the error state.
                jokeTextElement.innerText = “Unable to connect to the server =/”;
            });
        }
    });
})();

As you can see, making an HTTP request is super simple. Once we have the response text, a simple call to JSON.parse will turn it into a JS object we can inspect and make use of. If the response text is missing or not in valid JSON format, the parse call will throw an exception, and we’ll print a message that the server has returned invalid data. We also inspect the returned object for the fields we’re looking for. If we didn’t do this, and just used result.value.joke where “value” was missing, that line would throw an exception (essentially the JS equivalent of an Access Violation). If “value” were there but its “joke” property were missing, that would result in printing the text “undefined” to the screen. Since that’s not pretty, we check for the presence of those fields and print a slightly nicer error, if that case ever were to occur.

The second function we pass to .then() is an error handler for the promise. If anything in WinJS.xhr throws an exception, it will get captured by the promise and handed to us here. To keep this example simple we don’t bother inspecting the error. But in the real world you’ll often want to have more elaborate error handling than that.

Now when we run the app, we get this!

image

That’s the first one I got. Seemed appropriate enough 🙂

What’s next?

In part 2 we’ll look at using WinJS templating and databinding to display more than one joke at a time. So check back soon! Oh, and please use the comment section to let me know if this is helpful, if the format works for you, and if you have any questions about the content of the post. I fully understand that this first post spent a lot of time on some rather basic concepts for anyone already working with WinJS (and likely for many using similar JS libraries). I promise the content will get more interesting for you folks soon, after I’ve hopefully helped get the less experienced folks up to speed.

5 Comments
  1. Dev permalink

    Hi

    Looking forward to the rest of the series – I am enjoying you going over the basics rather than simply skipping/glossing over them. Can’t wait for more.

Trackbacks & Pingbacks

  1. Weekly Digest for Developers: Jan 26 – Feb 2, 2014 - Super Dev Resources
  2. Building Great #WinApps: Custom WinJS controls | BrandonLive
  3. Weekly Digest for Developers: Jan 26 – Feb 2, 2014 – linux-us-large.cloudapp.net
  4. Weekly Digest for Developers: Jan 26 – Feb 2, 2014 – superdev

Comments are closed.