Posts tagged with "windows-8"

Page Navigation in Windows 8 JavaScript Apps

I’d like to talk a bit about navigating in Metro apps using HTML/JavaScript. There are a few options for doing so, and as you probably know whenever there’s more than one way to do things, then you the developer have power but not necessarily clarity. The latter is what I hope to offer here.

First of all, the HTML/JavaScript that Metro apps are based on are identical to the HTML/JavaScript that websites are based on. It is entirely based on the standards. This is good because proprietary things are bad - generally speaking. This means that you can navigate exactly like you do in websites, but don’t. I’ll explain why not.

So you could navigate from default.html to page2.html like this…

<a href="page2.html">link to page 2</a>

But again… you should usually do this. Doing so changes the “top level document location”. This navigation looks something like this…

Where the user is no longer on the default.html page. For websites, it’s just fine to jump around by navigating the top level like this because you’re usually not too concerned about state, but in a full-fledged application, you usually are concerned with state and you can make your life easier by using the built-in navigation features that are provided by the VS2012 templates.

When you use the navigation functionality, a navigation looks more like this…

Notice that the user is still on default.html, but the contents of the second page have simply been loaded into what is called the contenthost. Now, if you loaded a bunch of script and styles on default.html and even declared some variables and set some state, you still have all of that, even though to the user it appears that you’ve navigated to a second page.

Implementing this is pretty straight-forward. Follow these steps…

  1. Get the navigate.js script file that comes with the Navigation Application project template in VS2012. You can either start with the Navigation Application project template and notice that navigate.js is already in your js folder, or you can create a throw-away Nav project and steal that file.

  2. Reference the navigate.js from your default.html file…

  3. Add a contenthost to your default.html file

And that’s it. After this has been implemented, then you are free to do things in your JavaScript like this…

WinJS.Navigation.navigate("/pages/page2/page2.html");

And you have the chance to pass some parameters without having to resort to query string parameters which can be cumbersome and restricting. To do this, you can pass a second parameter to the navigate function like this…

WinJS.Navigation.navigate("/pages/page2/page2.html", myDoohicky);

…where myDoohicky can be any JavaScript object you want.

Now, when might we actually perform this navigation? Well, in many cases it will be on some user action. For instance, let’s say the user is going to click a button and we want to navigate them to page2.html. Let’s see what that would look like…

HTML

<button id="myButton">go to page2</button>

JavaScript

ready: function (element, options) {
document.querySelector("#myButton").onclick = function (args) {
WinJS.Navigation.navigate("/pages/page2/page2.html", "test value");
};
}

Now let’s look at a bit more pragmatic example. Let’s say we are working in a grid (WinJS.UI.ListView technically) and when the user touches one of the tiles, we want to navigate to a second page with more details about that element.

This can be wired up much like the simple button example above, but likely the elements in our grid are data bound from some list that we have. In that case, perhaps the easiest way to implement this is by adding a function to the list and then bind the click function just like any of the data elements are bound. Here’s an example of that…

HTML

<div id="headertemplate" data-win-control="WinJS.Binding.Template">
<div>
<p data-win-bind="innerText:firstLetter"></p>
</div>
</div>
<div id="template" data-win-control="WinJS.Binding.Template">
<div data-win-bind="onclick:clickFunction">
<img class="img" data-win-bind="src:imageUrl" />
<p class="name" data-win-bind="innerText:title"></p>
</div>
</div>
<div id="list" data-win-control="WinJS.UI.ListView"></div>

JavaScript

ready: function (element, options) {

var titlesListGrouped = new WinJS.Binding.List().createGrouped(
function (i) { return i.title.charAt(0).toUpperCase(); },
function (i) { return { firstLetter: i.title.charAt(0).toUpperCase() }; }
);

var list = q("#list").winControl;
list.itemDataSource = titlesListGrouped.dataSource;
list.itemTemplate = q("#template");
list.groupDataSource = titlesListGrouped.groups.dataSource;
list.groupHeaderTemplate = q("#headertemplate");

WinJS.xhr({ url: "http://odata.netflix.com/Catalog/Titles?$format=json&amp;$top=200" })
.then(function (xhr) {
var titles = JSON.parse(xhr.response).d;
titles.forEach(function (i) {
var item = {
title: i.ShortName,
imageUrl: i.BoxArt.LargeUrl,
clickFunction: function(args) { WinJS.Navigation.navigate("/pages/page2/page2.html", item); }
};
item.clickFunction.supportedForProcessing = true;
titlesListGrouped.push(item);
});
});

}

Now, there’s a lot going on in the JavaScript file there, so let me break it down for you. First of all, I pulled this example from another post I did on creating a Netflix browser app utilizing their OData feed. If you want to know what’s going on with the call and the data binding, go check that out.

I added to it though. I changed what happens in the forEach loop. The reason I did is to illustrate how to bind to a function like you bind any other data property. Look in the HTML at the div just below the one with the id of template. I’m binding the onclick attribute to the clickFunction. That clickFunction is what I created in the forEach loop of the JavaScript. Notice, though, that there’s one funny thing we need to do to it. Since we are using this in the HTML it could be exploited and so we turn on strictProcessing for our app and that requires us to set _supportedForProcessing_ on any functions that we are going to call from the HTML. So, we set that to true for our function and we’re good to go.

I hope this brings the concept home for you. If you have questions, leave a comment below and I’ll be glad to try to help.

Permission to Get Excited

Anticipation. It’s good to wait. It’s good to hold on and hold out for what’s coming down the road.

I’m talking now about the Windows 8 Consumer Preview that is released tomorrow February 29, 2012. Along with Visual Studio 11, this new version of Windows is entirely exciting. If you weren’t at the //build conference and haven’t seen the keynote by Steven Sinofsky, watch it now. If you were there or you’ve already watched it online, then watch it again just like you watch your favorite movie again just before the sequel is released in the theater.

Windows 8 is a no-brainer in my book. It provides developer joy as well as user joy. It’s compatible with a plethora of computers already in the hands of computers as well as new and exciting devices on the shelf at your local tech store. It runs everything that ran before. It looks great and has a robust design language ready to support extend and launch your own personal or corporate brand. It is smaller in memory and CPU footprint and it appears to be entirely fast and fluid.

In short, it’s not a lateral step to move to a new device with Windows 8. It’s not a new device with a new OS and a new login. It’s an extension. A leap forward. It’s just plain exciting.

So let’s get excited, and let’s start building great apps for Windows 8! Let me know if you need any resources for getting started or for getting integrated into your local developer community for education and support in the process. Follow me on Twitter at @codefoster or email me at jeremy dot foster at microsoft dot com.