Part 3: PageControl objects and navigation (Windows Phone Store apps using JavaScript)

[ 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 ]

The "Hello, world" app you created in Part 1 and Part 2 of this series of tutorials has only a single page of content. Most real-world apps contain multiple pages.

You have multiple navigation patterns to choose from when you create a Windows Phone Store app. The Navigation patterns topic will help you choose the best navigation pattern for your app.

Note  

See the two primary navigation patterns, Flat navigation and Hierarchical navigation, in action in the App features, start to finish series.

 

In this tutorial, you copy the code from your "Hello, world" app into a new app that uses the Navigation App template, and then you add another page.

Learn how to:

  • Use the Navigation App project template to create an app that contains multiple pages of content.
  • Use PageControl objects to separate your code into modular units.
  • Use the single-page navigation model to navigate between pages.
  • Use an NavBar to provide navigation commands.

Before you start...

  • This is the third tutorial in a 5-part series. Before you begin this tutorial, read Part 2: Manage app lifecycle and state. This tutorial builds on the code you created in Part 1 and Part 2.

Nearly every website provides some form of navigation, usually in the form of hyperlinks that you click to go to a different page. Each page has its own set of JavaScript functions and data, a new set of HTML to display, style information, and so on. This navigation model is known as multi-page navigation. This design is fine for most websites, but it can pose problems for an app because it can be difficult to maintain state across multiple pages.

Another navigation model is single-page navigation, in which you use a single page for your app and load additional data into that page as needed. You still split your app into multiple files, but instead of moving from page to page, your app loads other documents into the main page. Because your app's main page is never unloaded, your scripts are never unloaded, which makes it easier to manage state, transitions, or animations. We recommend that apps use the single-page navigation model.

To help you create apps that use the single-page navigation model, the Windows Library for JavaScript (WinJS) provides the WinJS.UI.Pages.PageControl object. There's also the Navigation App project template, which provides some additional navigation infrastructure. In the following steps, you use this template to create a new project.

Step 1: Create a new Navigation App in Visual Studio

First, create a new app named HelloWorldWithPages that uses the Navigation App template.

To create a new Navigation App

  1. In Microsoft Visual Studio Express 2013 for Windows, on the File menu, click New Project.

  2. In the left pane of the New Project dialog, expand Installed, expand Templates, expand JavaScript, expand Store Apps, and then select the Windows Phone template type. The dialog's center pane displays a list of project templates for JavaScript.

    For this tutorial, use the Navigation App template.

  3. In the center pane, select the Navigation App template.

  4. In the Name text box, type "HelloWorldWithPages".

  5. Click OK to create the project.

    Visual Studio creates your project and displays it in Solution Explorer.

Your new Navigation App contains a few more files than your "Hello, world" app. It includes these new files:

  • /pages/home/home.css, /pages/home/home.html, and /pages/home/home.js

    These three pages define a PageControl for the app's home page. A PageControl is made up of an HTML file, a JavaScript file, and a Cascading Style Sheets (CSS) file. A PageControl is a modular unit of HTML, CSS, and JavaScript that can be navigated to (like an HTML page) or used as a custom control. You can use PageControl objects to split a large app into smaller, more manageable portions.

    PageControl objects support several methods that makes using them in your app easier than using a collection of loose HTML, CSS, and JavaScript pages. You'll learn more about these methods in a later step.

  • /js/navigator.js

    This file provides the PageControlNavigator helper class that you can use to display PageControl objects and navigate between them. You don't need it to display a PageControl, but it can make using them easier.

This is the default.html page of your new app:

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

    <!-- WinJS references -->
    <!-- At runtime, ui-themed.css resolves to ui-themed.light.css or ui-themed.dark.css 
    based on the user’s theme setting. This is part of the MRT resource loading functionality. -->
    <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>

    <!-- HelloWorldWithPages references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
    <script src="/js/navigator.js"></script>
</head>
<body class="phone"> 
    <div id="contenthost" data-win-control="Application.PageControlNavigator" 
        data-win-options="{home: '/pages/home/home.html'}"></div>
    <!-- <div id="appbar" data-win-control="WinJS.UI.AppBar">
        <button data-win-control="WinJS.UI.AppBarCommand" 
            data-win-options="{id:'cmd', label:'Command', icon:'placeholder'}" type="button"></button>
    </div> -->
</body>
</html>

The body of the file contains two elements: A div element for the PageControlNavigator and a commented-out div for an AppBar. You can ignore the app bar for now and take a closer look at the first div element.

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

This div element creates a PageControlNavigator control. The PageControlNavigator loads and displays your home page. Use the data-win-options attribute to tell it which page to load (/pages/home/home.html).

Run the app.

Although it's not obvious, the app is actually showing both default.html and home.html. It's similar to using an iframe to display a HTML page inside another HTML page.

Step 2: Copy your HTML and CSS content from your "Hello, world" app

Your new app has two HTML pages: default.html and home.html. Where do you put your content?

  • Use default.html for UI that should always be present, no matter which page the app is displaying. For example, you can use default.html to host a navigation bar.

  • Use pages, such as home.html, for content that makes up an individual screen in the app.

Open home.html and take a look at some of the markup it contains.

  • It has a head element that contains references to the Windows Library for JavaScript code and style sheets. It also contains references to the app's default style sheet (default.css) and to the other files that make up the home page (home.css and home.js).

    <head>
        <meta charset="utf-8" />
        <title>homePage</title>
    
        <!-- WinJS references -->
        <link href="//Microsoft.Phone.WinJS.2.1/css/ui-dark.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>
    
        <link href="/css/default.css" rel="stylesheet" />
        <link href="/pages/home/home.css" rel="stylesheet" />
        <script src="/pages/home/home.js"></script>
    </head>
    
  • It has a page header area that includes a title element.

            <header aria-label="Header content" role="banner">
                <h1 class="titlearea win-type-ellipsis">
                    <span class="pagetitle">Welcome to App3!</span>
                </h1>
            </header>
    
  • It has a section for your main content.

            <section aria-label="Main content" role="main">
                <p>Content goes here.</p>
            </section>
    

Next, add the content from your "Hello, world" app to the home page (home.html) of your new HelloWorldWithPages project.

To add the HTML and CSS content from your "Hello, world" app

  1. Copy your final HTML content from the default.html file of your "Hello, world" app into the main content section of the /pages/home/home.html in your new project.

    <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 HelloWorldWithPages!</span>
                </h1>
            </header>
            <section aria-label="Main content" role="main">
    
                <!-- Copied from "Hello, world" -->
                <h1 class="headerClass">Hello, world!</h1>
                <div class="mainContent">
                    <p>What's your name?</p>
                    <input id="nameInput" type="text" />
                    <button id="helloButton">Say "Hello"</button>
                    <div id="greetingOutput"></div>
                    <br />
                    <div id="toggleControlDiv" data-win-control="WinJS.UI.ToggleSwitch" 
                        data-win-options="{title: 'Greeting Color'}"></div>
                </div>
            </section>
        </div>
    </body>
    
  2. Move the heading content that you copied to the h1 element that home.html provides for you. Because home.html already contains a main content section, remove the "mainContent" div element that you copied (but leave its contents).

    <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 HelloWorldWithPages!</span>
                </h1>
            </header>
            <section aria-label="Main content" role="main">
                <p>What's your name?</p>
                <input id="nameInput" type="text" />
                <button id="helloButton">Say "Hello"</button>
                <div id="greetingOutput"></div>
                <br />
                <div id="toggleControlDiv" data-win-control="WinJS.UI.ToggleSwitch" 
                    data-win-options="{title: 'Greeting Color'}"></div>
            </section>
        </div>
    </body>
    
  3. Each PageControl has its own CSS file.

    Copy the greetingOutput and toggleOn styles from the default.css file you created in Part 1: Create a "Hello, world!" app to home.css.

    .homepage section[role=main] {
        margin-left: 24px;
        margin-right: 24px;
    }
    
    .fragment section[role=main] {
        width: calc(100% - 48px)
    }
    
    .fragment header[role=banner] .titlearea {
        -ms-grid-column: 3;
        margin-top: 37px;
        margin-left: -96px;
    }
    
    #greetingOutput {
        font-size:x-large; 
    }
    
    .toggle-on {
        color:blue; 
    }
    
  4. Run the app.

    You've recreated the content from your original "Hello, world" app. Next, add interactivity by copying your "Hello, world" event handlers.

Step 3: Copy your event handlers

Each PageControl has its own JavaScript file. Take a look at the JavaScript file that Visual Studio created for your "home" PageControl, home.js:

(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.
        }
    });
})();

This file looks quite different than your default.js file. For one thing, it's much shorter. That's because default.js already handles activation and core app logic. Each PageControl only needs to contain logic for the page itself.

One of the first lines of code, a call to the WinJS.UI.Page.define function, creates the PageControl object. This function takes two parameters: the URI of the page ("/pages/home/home.html" in this example), and an object that defines the members of the PageControl. You can add any type of member you want. You can also implement a set of special members, described by the IPageControlMembers interface, that automatically get called by the app when you use the PageControl.

The home.js file created by the template defines one of these special members, the ready function. The ready function is called after your page is initialized and rendered. This is a good place to attach event handlers.

You might notice that the code doesn't include a call to WinJS.UI.processAll. That's because the PageControl calls it for you automatically. By the time the ready function is called, WinJS.UI.processAll has already been called and has completed its processing.

To add event handlers

  1. In Part 1: Create a "Hello, world" app and Part 2: Manage app life cycle and state, you defined three event handlers: buttonClickHandler, toggleChanged, and nameInputChanged. Copy these event handlers to your home.js file and make them members of your PageControl. Add them after the ready function that the template created for you.

        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.
            },
    
            buttonClickHandler: function (eventInfo) {
                // Get the user's name input
                var userName = document.getElementById("nameInput").value;
    
                // Create the greeting string and set the greeting output to it
                var greetingString = "Hello, " + userName + "!";
                document.getElementById("greetingOutput").innerText = greetingString;
    
                // Save the session data. 
                WinJS.Application.sessionState.greetingOutput = greetingString;
            },
    
            toggleChanged: function (eventInfo) {
                // Get the toggle control
                var toggleControl = document.getElementById("toggleControlDiv").winControl;
    
                // Get the greeting output
                var greetingOutput = document.getElementById("greetingOutput");
    
                // Set the CSS class for the greeting output based on the toggle's state
                if (toggleControl.checked == true) {
                    greetingOutput.setAttribute("class", "toggle-on");
                }
                else {
                    greetingOutput.removeAttribute("class", "toggle-on");
                }
    
                // Store the toggle selection for multiple sessions.
                var appData = Windows.Storage.ApplicationData.current;
                var roamingSettings = appData.roamingSettings;
                roamingSettings.values["toggleSelection"] = toggleControl.checked;
            },
    
            nameInputChanged: function (eventInfo) {
                var nameInput = eventInfo.srcElement;
    
                // Store the user's name input
                WinJS.Application.sessionState.nameInput = nameInput.value;
            }
        });
    
  2. Now you need to attach your event handlers. In Part 1 and Part 2 you created a then function for the Promise returned by WinJS.UI.processAll. Things are a little simpler now because you can use the ready function to attach your event handlers. The ready function is called after the PageControl has automatically called WinJS.UI.processAll.

    Copy the code that attaches your event handlers to the ready function in home.js, modifying the reference to each handler to include the this prefix.

            // 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.
                // Retrieve the div that hosts the Toggle control.
                var toggleControlDiv = document.getElementById("toggleControlDiv");
    
                // Retrieve the actual Toggle control.
                var toggleControl = toggleControlDiv.winControl;
    
                // Register the event handler. 
                toggleControl.addEventListener("change", this.toggleChanged, false);
    
                // Retrieve the button and register your event handler. 
                var helloButton = document.getElementById("helloButton");
                helloButton.addEventListener("click", this.buttonClickHandler, false);
    
                // Retrieve the input element and register your
                // event handler.
                var nameInput = document.getElementById("nameInput");
                nameInput.addEventListener("change", this.nameInputChanged);
            },
    
  3. Run the app. It should work just as it did before: when you enter a name and click the button, it displays a greeting. When you flip the ToggleSwitch, the color of the greeting changes.

Step 4: Restore the app's state

You've almost recreated the functionality you had in your "Hello, world" app. The only thing you need to do now is restore the app's state when the user launches it.

You might remember that you had two types of app state to restore:

  • The ToggleSwitch's state. You restore this regardless of how the app was shut down.
  • The user name and greeting. You only restore this state if the app was successfully terminated the last time it ran.

To restore app state

  1. Copy the code that restores the state of the ToggleSwitch from the "Hello, world" app. Add the code to the ready function in home.js.

            // 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.
                // Retrieve the div that hosts the Toggle control.
                var toggleControlDiv = document.getElementById("toggleControlDiv");
    
                // Retrieve the actual Toggle control.
                var toggleControl = toggleControlDiv.winControl;
    
                // Register the event handler. 
                toggleControl.addEventListener("change", this.toggleChanged, false);
    
                // Retrieve the button and register our event handler. 
                var helloButton = document.getElementById("helloButton");
                helloButton.addEventListener("click", this.buttonClickHandler, false);
    
                // Retrieve the input element and register our
                // event handler.
                var nameInput = document.getElementById("nameInput");
                nameInput.addEventListener("change", this.nameInputChanged);
    
                // Restore app data. 
                var roamingSettings = Windows.Storage.ApplicationData.current.roamingSettings;
    
                // Restore the Toggle selection.
                var toggleSelection = roamingSettings.values["toggleSelection"];
                if (toggleSelection) {
                    toggleControl.checked = toggleSelection;
    
                    // Apply the properties of the toggle selection
                    var greetingOutput = document.getElementById("greetingOutput");
                    if (toggleControl.checked == true) {
                        greetingOutput.setAttribute("class", "toggle-on");
                    }
                    else {
                        greetingOutput.removeAttribute("class", "toggle-on");
                    }
                }
    
  2. You only want to restore the input box contents and personalized greeting if the app was successfully terminated the last time it ran. Unfortunately, your PageControl doesn't provide a built-in way to check the app's previous execution state: that info is provided to the onactivated event handler in your default.js file. But there's an easy solution to this problem: you just need to save the app's previous execution state in the sessionState object so that your PageControl can access it.

    1. In your default.js file, add code to your onactivated handler to save the previous execution state. Save the state by adding a property to the sessionState object named previousExecutionState.

          app.addEventListener("activated", 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.
                  }
      
                  // Save the previous execution state. 
                  WinJS.Application.sessionState.previousExecutionState =
                      args.detail.previousExecutionState;
      
                  nav.history = app.sessionState.history || {};
                  nav.history.current.initialPlaceholder = true;
      
                  // 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);
              }
          });
      
    2. In the home.js file, add code to your ready method that checks the previousExecutionState data. If the previous execution state is terminated, restore the personalized greeting (you can copy your code that does this from the default.js file in your "Hello, world" app.)

                  // If the app was terminated last time it ran, restore the personalized
                  // greeting. 
                  if (
                      WinJS.Application.sessionState.previousExecutionState
                      === Windows.ApplicationModel.Activation.ApplicationExecutionState.terminated) {
                      var outputValue = WinJS.Application.sessionState.greetingOutput;
                      if (outputValue) {
                          var greetingOutput = document.getElementById("greetingOutput");
                          greetingOutput.innerText = outputValue;
                      }
      
                  }
      

      Here's the complete ready method.

              // 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.
                  // Retrieve the div that hosts the Toggle control.
                  var toggleControlDiv = document.getElementById("toggleControlDiv");
      
                  // Retrieve the actual Toggle control.
                  var toggleControl = toggleControlDiv.winControl;
      
                  // Register the event handler. 
                  toggleControl.addEventListener("change", this.toggleChanged, false);
      
                  // Retrieve the button and register our event handler. 
                  var helloButton = document.getElementById("helloButton");
                  helloButton.addEventListener("click", this.buttonClickHandler, false);
      
                  // Retrieve the input element and register our
                  // event handler.
                  var nameInput = document.getElementById("nameInput");
                  nameInput.addEventListener("change", this.nameInputChanged);
      
                  // Restore app data. 
                  var roamingSettings = Windows.Storage.ApplicationData.current.roamingSettings;
      
                  // Restore the Toggle selection.
                  var toggleSelection = roamingSettings.values["toggleSelection"];
                  if (toggleSelection) {
                      toggleControl.checked = toggleSelection;
      
                      // Apply the properties of the toggle selection
                      var greetingOutput = document.getElementById("greetingOutput");
                      if (toggleControl.checked == true) {
                          greetingOutput.setAttribute("class", "toggle-on");
                      }
                      else {
                          greetingOutput.removeAttribute("class", "toggle-on");
                      }
                  }
      
                  // If the app was terminated last time it ran, restore the greeting
                  // and name output
                  if (
                      WinJS.Application.sessionState.previousExecutionState
                      === Windows.ApplicationModel.Activation.ApplicationExecutionState.terminated) {
                      var outputValue = WinJS.Application.sessionState.greetingOutput;
                      if (outputValue) {
                          var greetingOutput = document.getElementById("greetingOutput");
                          greetingOutput.innerText = outputValue;
                      }
                      var inputValue = WinJS.Application.sessionState.nameInput;
                      if (inputValue) {
                          var nameInput = document.getElementById("nameInput");
                          nameInput.value = inputValue;
                      }
                  }
              },
      
  3. Run the app. You've now duplicated the functionality in your original "Hello, world" app.

Step 5: Add another page

Most apps contain several pages. Now add another page to your app. Because you're using the Navigation App template, it's easy to add additional pages.

To add another page

  1. In Solution Explorer, right-click the pages folder, and then click Add > New Folder.

  2. Rename the folder "page2".

  3. Right-click the page2 folder, and then click add Add > New Item....

  4. In the Add New Item dialog, click Page Control from the list. In the Name text box, type "page2.html".

  5. Click Add to add the PageControl. The new PageControl appears in Solution Explorer.

    The new PageControl has three files: page2.css, page2.html, and page2.js.

  6. Add the default WinJS CSS and JavaScript library references to the page header (you can copy and paste them from your home.html page).

    <head>
        <meta charset="utf-8" />
        <title>page2</title>
        <!-- WinJS references -->
    
        <link href="//Microsoft.Phone.WinJS.2.1/css/ui-dark.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>
    
        <link href="page2.css" rel="stylesheet" />
        <script src="page2.js"></script>
    </head>
    

You've created a new page. In the next step, you learn how to navigate to it.

Step 6: Use the navigate function to move between pages

Right now, you have a second page but no way for the user to get to it. You need to update your home.html page by adding a link to page2.html.

To navigate between pages

  1. Open your home.html page and add a link to page2.html.

    <body>
        <!-- The content that will be loaded and displayed. -->
        <div class="fragment homepage">
            <header aria-label="Header content" role="banner">
                <h1 class="titlearea win-type-ellipsis">
                    <span class="pagetitle">Hello, world!</span>
                </h1>
            </header>
            <section aria-label="Main content" role="main">
                <p>What's your name?</p>
                <input id="nameInput" type="text" />
                <button id="helloButton">Say "Hello"</button>
                <div id="greetingOutput"></div>
                <br />
                <div id="toggleControlDiv" data-win-control="WinJS.UI.ToggleSwitch" data-win-options="{title: 'Greeting Color'}"></div>
    
                <!--A hyperlink to page2.html. -->
                <p><a href="/pages/page2/page2.html">Go to page 2.</a></p>
            </section>
        </div>
    </body>
    
  2. Run the app and click the link. It seems to work: the app displays page2.html.

However, there's a problem: the app performed a top-level navigation. Instead of navigating from home.html to page2.html, it navigates from default.html to page2.html.

What you want instead is to replace the content of home.html with page2.html.

Fortunately, the PageControlNavigator control makes performing this type of navigation fairly easy. The PageControlNavigator code (in your app's navigator.js file) handles the WinJS.Navigation.navigated event for you. When the event occurs, the PageControlNavigator loads the page specified by the event.

The WinJS.Navigation.navigated event occurs when you use the WinJS.Navigation.navigate, WinJS.Navigation.back, or WinJS.Navigation.forward functions to navigate.

You need to call WinJS.Navigation.navigate yourself rather than using the hyperlink's default behavior. You could replace the link with a button and use the button's click event handler to call WinJS.Navigation.navigate. Or you could change the default behavior of the hyperlink so that when the user clicks a link, the app uses WinJS.Navigation.navigate to navigate to the link target. To do this, handle the hyperlink's click event and use the event to stop the hyperlink's default navigation behavior, and then call the WinJS.Navigation.navigate function and pass it the link target.

To override the default hyperlink behavior

  1. In your home.js file, define a click event handler for your hyperlinks and make it a member of your PageControl. Name it linkClickEventHandler, and then add it after the nameInputChanged handler.

            nameInputChanged: function (eventInfo) {
                var nameInput = eventInfo.srcElement;
    
                // Store the user's name for multiple sessions.
                var appData = Windows.Storage.ApplicationData.current;
                var roamingSettings = appData.roamingSettings;
                roamingSettings.values["userName"] = nameInput.value;
            },        
    
    
            linkClickEventHandler: function (eventInfo) {
    
            }
    
  2. Call the preventDefault method to prevent the default link behavior (navigating directly to the specified page).

            linkClickEventHandler: function (eventInfo) {
                eventInfo.preventDefault();
    
            }
    
  3. Retrieve the hyperlink that triggered the event.

            linkClickEventHandler: function (eventInfo) {
                eventInfo.preventDefault();
                var link = eventInfo.target;
    
            }
    
  4. Call the WinJS.Navigation.navigate function and pass it the link target. (Optionally, you could also pass a state object that describes the state for that page. For more information, see the WinJS.Navigation.navigate page.)

            linkClickEventHandler: function (eventInfo) {
                eventInfo.preventDefault();
                var link = eventInfo.target;
                WinJS.Navigation.navigate(link.href);
            }
    
  5. In the home.js file's ready function, attach the event handler to your hyperlinks.

    The WinJS provides a WinJS.Utilities.query function that makes it easy to retrieve a number of elements on the page. The WinJS.Utilities.query function returns a QueryCollection, which provides additional methods for attaching and removing event handlers. Use the WinJS.Utilities.query collection and the listen method to attach your linkClickEventHandler.

            // 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.
    
                WinJS.Utilities.query("a").listen("click", 
                    this.linkClickEventHandler, false);
    

    The nice thing about this approach is that it will work for any number of links on the page. You only have one link right now, but with this approach, you could add more links and you wouldn't have to change your code.

  6. Run the app and click the link for page2.html.

    Now the page displays using the proper navigation pattern.

Summary

Congratulations, you've finished the third tutorial! You learned how to create a project that uses the Navigation App template and how to use PageControl objects.

Download the sample

Do you need more info, or want to check your work? Download the Getting started with JavaScript sample.

Getting started with JavaScript: Complete code for the tutorial series

For designers

Navigation patterns

Command patterns

Layout

Guidelines for back buttons

Guidelines for hub controls

Guidelines for app bars

Making the app bar accessible

For developers

Navigation and navigation history sample

Adding app bars

Adding nav bars

Navigating between pages

HTML Hub control sample

HTML AppBar control sample

HTML NavBar control sample

WinJS.UI.Hub object

WinJS.UI.AppBar object

WinJS.UI.NavBar object

WinJS.UI.BackButton object