Dela via


Coding basic apps (HTML)

[ This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation ]

This topic shows you the structure of a basic app and introduces you to some of the Windows app using JavaScript coding conventions.

Prerequisites

We assume that you can create a basic Windows Runtime app using JavaScript as described in Create your first Windows Runtime app using JavaScript.

Contents of a basic app

When you use Microsoft Visual Studio to create a new project that uses the Blank Application template, it creates an app that contains a handful of files:

  • default.html

    The app's start page. This is the page that shows when your app is launched. This file contains references to default.js, the Windows Library for JavaScript files and style sheets, and the app's own style sheet, default.css.

  • /js/default.js

    JavaScript code that specifies how the app behaves when it's started. This file contains code for handling your app's lifecycle. The template-generated default.js handles app activation, but a typical app will also handle suspending and resuming events.

  • /css/default.css

    The app's Cascading Style Sheets (CSS) styles. Here you can define your own styles or override existing the ones provided by the WinJS.

  • /References/WinJS SDK

    The WinJS: a set of styles, controls, and utilities for creating apps.

  • package.appmanifest

    The app manifest. This file lists the contents of your app and describes its capabilities. It also specifies which page to use as the app's start page. When you use Visual Studio to add more files to your app, it automatically updates your app manifest.

  • /images

    The template also includes several image files, like splashscreen.png for the splash screen image, and storelogo.png, which is used for the Windows Store.

The default.html and default.js files

Regardless of which Visual Studio template you use to create your Windows Runtime app using JavaScript, it contains a default.html and default.js file.

Here's the markup for default.html that gets generated for you when you create a new project using the Blank Application template.

default.html for Windows apps

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>BasicSampleApp</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>

    <!-- BasicSampleApp references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
</head>
<body>
    <p>Content goes here</p>
</body>
</html>

default.html for Windows Phone apps

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>BasicSampleApp</title>

    <!-- WinJS references -->
    <link href="/css/ui-themed.css" rel="stylesheet" />
    <script src="//Microsoft.Phone.WinJS.2.1/js/base.js"></script>
    <script src="//Microsoft.Phone.WinJS.2.1/js/ui.js"></script>

    <!-- BasicSampleApp references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
</head>
<body>
    <p>Content goes here</p>
</body>
</html>

Here's the code for the default.js file that gets generated for you automatically when you create a new project.

(function () {
    "use strict";

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

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            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.
            }
            args.setPromise(WinJS.UI.processAll());
        }
    };

    app.oncheckpoint = function (args) {
        // TODO: This application is about to be suspended. Save any state
        // that needs to persist across suspensions here. You might use the
        // WinJS.Application.sessionState object, which is automatically
        // saved and restored across suspension. If you need to complete an
        // asynchronous operation before your application is suspended, call
        // args.setPromise().
    };

    app.start();
})();

The app lifecycle

Most of the code in the default.js file handles the app lifecycle. The app lifecycle begins when the app starts, and ends when the app is closed. The project templates include a generic pattern for managing the app lifecycle.

The code provided by the template checks whether the app was started from the Start screen and calls WinJS.UI.processAll. The WinJS.UI.processAll loads all the WinJS controls that you declared in your HTML file. If you have code that needs to run when the app sets up its initial state, include it in the handler for the activated event.

Note  Performing a lot of work during activation will make your app seem unresponsive. If possible, defer expensive operations until after your app is loaded.

 

The template doesn't include code to handle suspending, resuming, or terminating the app. For more info about handling these states, see Application lifecycle.

Anonymous functions and strict mode

If you're used to programming for websites, you might find a few aspects of the code unusual. For one, the entire file is wrapped in an anonymous function:

(function () {
    ...
})();

Why is that? JavaScript has two scopes: global and local. If you declare a variable outside of any function definition, it is a global variable, and its value is accessible and modifiable throughout your program. If you declare a variable inside of a function definition, that variable is local. It cannot be accessed by anything outside the function.

By wrapping your code in an anonymous function, you make it private. Wrapping your code in an anonymous function is a good coding practice because it limits the scope of your code and avoids polluting the global namespace. It also makes it easier to avoid naming conflicts or situations where you accidently modify a value that you didn't intend to.

Basically, you can use anonymous functions to create private members in JavaScript, a language that doesn't otherwise support them.

If you're wondering what the extra parenthesis at the end of the function declaration does, it invokes the anonymous function:

(function () {
    ...
})(); // Makes the function self-invoking.

The default.js file also declares that it runs in strict mode:

(function () {
    "use strict"; // Declares strict mode. 

    ...

})();

Strict mode provides better error-checking for your JavaScript code. When you use strict mode, your code is subject to a tighter set of restrictions than JavaScript normally allows. For example, you can't use a variable without declaring it, write to a read-only property, or use a with statement. These restrictions help you write better code and reduce the likelihood of introducing errors into your app.

For more info about strict mode, see Strict Mode in the JavaScript Language Reference.

Adding event handlers

While wrapping your code in an anonymous function provides many advantages, it forces you to change how you write your code. For example, you need to change how you handle events.

Suppose that you add a button to your default.html page. When the user clicks the button, you want to display the x- and y- coordinates of the point clicked, so you add a paragraph element for displaying that info. The next example adds these elements to the BODY tags in the default.html file, and it adds a div element to contain them.

<body>
    <div>
        <button id="button1">An HTML button</button>
        <p id="button1Output"></p>
    </div>
</body>

Now, define an event handler for the button's click event in your default.js file. Most event handlers take a single argument, an Event object that contains info about the event. Other events might return other types of event info objects that provide info specific for that event.

The click event provides a MouseEvent object that contains info about the event, such as which mouse button was pressed and which object fired the event. This example creates a click event handler that uses the MouseEvent object to obtain the x- and y-coordinates of the point that the user clicked.

(The click event also responds to touch and keyboard interaction. The examples in this topic assume that the user is clicking with a mouse. )

(function () {
    "use strict";

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

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            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.
            }
            args.setPromise(WinJS.UI.processAll());
        }
    };

    app.oncheckpoint = function (args) {
        // TODO: This application is about to be suspended. Save any state
        // that needs to persist across suspensions here. You might use the
        // WinJS.Application.sessionState object, which is automatically
        // saved and restored across suspension. If you need to complete an
        // asynchronous operation before your application is suspended, call
        // args.setPromise().
    };

    // The click event handler for button1
    function button1Click(mouseEvent) {
        var button1Output = document.getElementById("button1Output");
        button1Output.innerText =
            mouseEvent.type
            + ": (" + mouseEvent.clientX + "," + mouseEvent.clientY + ")";

    }

    app.start();
})();

The only thing you need to do now is register the event handler with the button. You might be inclined to register the handler by setting the button's onclick attribute.

        <button id="button1" onclick="button1Click(event)">An HTML button</button>

It doesn't work, though. When you run the app and click the button, you get this exception:

Unhandled exception at line 21, column 39 in ms-appx://77d9a962-d259-45b1-9f04-3abf289aff57-6mtxa77c2r4nt/default.html

0x800a1391 - JavaScript runtime error: 'button1Click' is undefined

But your default.js file contains a definition for button1Click. Why doesn't it work?

That's because everything inside the anonymous function in default.js is local, or private. Your default.html can't access the button1Click function.

(function () {
    
    // default.html can't access anything inside this function.
 
})();

There are two ways to work around this restriction. You can make button1Click publicly accessible, or you can attach the event handler in code. The recommended approach is to attach the event handler in code, but we show you both ways. (To jump right to the recommended approach, see Attaching an event handler in code.)

Making a member publicly accessible

Every Windows Runtime app using JavaScript includes the WinJS. One of the useful things that the WinJS provides is a way to define namespaces and classes. The WinJS.Namespace.define function creates a public namespace. It takes two parameters: the name of the namespace to create, and an object that contains one or more property/value pairs. Each property is the public name of the member, and each value is a variable, property, or function to expose.

This example creates a namespace named startPage that contains a single member named clickEventHandler. The value of clickEventHandler is the button1Click function you defined earlier.

    var namespacePublicMembers = { clickEventHandler: button1Click };
    WinJS.Namespace.define("startPage", namespacePublicMembers);

Here's the complete default.js file, so you can see how the namespace declaration fits in with the rest of the file.

(function () {
    "use strict";

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

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            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.
            }
            args.setPromise(WinJS.UI.processAll());
        }
    };

    app.oncheckpoint = function (args) {
        // TODO: This application is about to be suspended. Save any state
        // that needs to persist across suspensions here. You might use the
        // WinJS.Application.sessionState object, which is automatically
        // saved and restored across suspension. If you need to complete an
        // asynchronous operation before your application is suspended, call
        // args.setPromise().
    };

    // The click event handler for button1
    function button1Click(mouseEvent) {
        var button1Output = document.getElementById("button1Output");
        button1Output.innerText =
            mouseEvent.type
            + ": (" + mouseEvent.clientX + "," + mouseEvent.clientY + ")";

    }

    var namespacePublicMembers = { clickEventHandler: button1Click };
    WinJS.Namespace.define("startPage", namespacePublicMembers);

    app.start();
})();

Now that the event handler is exposed publicly as startPage.clickEventHandler, you can use it to set the button's onclick attribute.

      <button id="button1" onclick="startPage.clickEventHandler(event)">An HTML button</button>

Now when you run the app, the event handler works properly.

That's one way to connect an event handler. The other way is to attach the event handler in code. Let's take a look.

Attaching an event handler in code

Another way (the recommended way) to attach an event handler is to use JavaScript to retrieve the control, then use the addEventListener method to register the event. The question is, when should you retrieve the control? You could just add it anywhere to your JavaScript code, but then there's a chance it might get called before the control exists.

The answer for most HTML files is to provide a then or done function for the Promise returned by the WinJS.UI.processAll method. (For Page controls, you can use the ready function instead.)

What's a Promise? To provide responsive user experience, many WinJS and Windows Runtime functions execute asynchronously. That way your app can continue to respond to user interactions while performing work in the background. Instead of directly returning a value, an asynchronous function returns a Promise object for a value. For more info about asynchronous programming, see Asynchronous programming in JavaScript.

            args.setPromise(WinJS.UI.processAll().then(function () {
                var button1 = document.getElementById("button1");
                button1.addEventListener("click", button1Click, false);
                })
            );

Here's the complete code for default.html and default.js:

default.html for Windows apps

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>BasicSampleApp</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>

    <!-- BasicSampleApp references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
</head>
<body>
    <p>Content goes here</p>
</body>
</html>

default.html for Windows Phone apps

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>BasicSampleApp</title>

    <!-- WinJS references -->
    <link href="/css/ui-themed.css" rel="stylesheet" />
    <script src="//Microsoft.Phone.WinJS.2.1/js/base.js"></script>
    <script src="//Microsoft.Phone.WinJS.2.1/js/ui.js"></script>

    <!-- BasicSampleApp references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
</head>
<body>
    <p>Content goes here</p>
</body>
</html>
(function () {
    "use strict";

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

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            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.
            }
            args.setPromise(WinJS.UI.processAll().then(function () {
                var button1 = document.getElementById("button1");
                button1.addEventListener("click", button1Click, false);
                })
            );
        }
    };

    app.oncheckpoint = function (args) {
        // TODO: This application is about to be suspended. Save any state
        // that needs to persist across suspensions here. You might use the
        // WinJS.Application.sessionState object, which is automatically
        // saved and restored across suspension. If you need to complete an
        // asynchronous operation before your application is suspended, call
        // args.setPromise().
    };

    // The click event handler for button1
    function button1Click(mouseEvent) {
        var button1Output = document.getElementById("button1Output");
        button1Output.innerText =
            mouseEvent.type
            + ": (" + mouseEvent.clientX + "," + mouseEvent.clientY + ")";

    }

    // You don't need the following code if you don't define the 
    // onclick attribute in the HTML markup of the button.
    //var namespacePublicMembers = { clickEventHandler: button1Click };
    //WinJS.Namespace.define("startPage", namespacePublicMembers);

    app.start();
})();

Adding pages and navigating between them

The Blank Application template works well for a very simple app, but when you write a more complex app, you'll probably want to divide your content into multiple files.

A traditional website might have a series of pages that you navigate between using hyperlinks. Each page has its own set of JavaScript functions and data, a new set of HTML to display, style info, and so on. This navigation model is known as multi-page navigation.

Unlike a traditional website, a Windows Runtime app using JavaScript works best when it uses the single-page navigation model. In this model, you use a single page for your app and load additional data ('fragments') into that page as needed.

That means that your app never navigates away from its default.html page. Always make the default.html and default.js files your app's start up page. They define the outmost UI for your app (such as the AppBar) and handle the application lifecycle.

If you never navigate away from default.html, how do you bring in content from other pages? There are a few different ways.

  • You can use HtmlControl to display HTML from another page that doesn't contain interactivity (HtmlControl doesn't support the loading of JavaScript).
  • You can create a PageControl and display it on your main page. A PageControl is set of HTML, JavaScript, and CSS that you can display inside another HTML page, much like you would another control. For more info about creating Page controls, see Adding Page controls.
  • You can use a WebView.md) control to display web-based content in your app. The WebView control can access most HTML5 features from external pages. It also maintains its own history stack and allows for navigating forward and backwards, or reloading a page.
  • You can also use DOM methods to incorporate content from other pages.

For more info about navigation, see Supporting navigation.

Choosing the best template

The Blank Application template contains the bare-minimum code necessary to create a Windows Runtime app using JavaScript. Visual Studio provides several templates that might provide a better starting point, depending on what you want your app to do. For detailed info about these templates, see JavaScript project templates for Windows Runtime apps.

Summary and next steps

You learned about the components of a basic app and how to work with Windows Runtime app using JavaScript coding conventions. The next topic, HTML, CSS, and JavaScript features and differences, describes more of the differences between coding for a Windows Runtime app using JavaScript and coding for a website.

JavaScript project templates for Windows Runtime apps

Application lifecycle

Quickstart: adding HTML controls and handling events

Quickstart: Adding WinJS controls and styles

Supporting navigation