codefoster | to inform and to inspire
Jeremy Foster
@codefoster

Metro Design by Blink Interactive

by Jeremy Foster 24. June 2012 21:30

Last Friday my user group (“The Ocho”) met and heard a special presentation on Metro Design thanks to Blink Interactive.

Valentina and Christina are UW students and interns at Blink and gave us a ton of information about user centric design and then the history and concepts behind Metro design.

I promised that I’d post their slide deck for those that want to take a look, so here it is.

If you were there with us, thanks for joining. If you weren’t, then look up our next meeting at http://www.meetup.com/theocho. Maybe we’ll see you there.

Windows 8 Design_v3.pdf (3.69 mb)

Tags:

Design | Windows 8

How to Make Your Grid Pan Automatically

by Jeremy Foster 24. June 2012 09:19

I got a question at an event a few weeks ago that sounded at first like it was going to implicate a rather complicated answer. In the end, it turned out to be not so bad.

The question was…

On the start screen when the user moves his mouse to the edge, the tiles pan automatically. How do I make the grid in my app work just like that?

And the answer - or rather an answer is here…

var timer = null; 
element.querySelector(".groupeditemslist").onmousemove = function (ev) { 
    clearInterval(timer); 
    timer = -1; 
    if (ev.screenX > (document.body.scrollWidth - 50)) 
        timer = setInterval(function () { listView.scrollPosition += 30; }, 1); 
    else if (ev.screenX < 50) 
        timer = setInterval(function () { listView.scrollPosition -= 30; }, 1); 
};

Let me unpack that for you.

When the user’s mouse is within the grid (that’s the .groupeditemslist), then check the event argument that our event function received and see what the location of the user’s mouse is on the screen (that’s screenX).

If it is withing 50 pixels of the right side of the page (that’s the document.body.scrollWidth) then set timer to a new interval that runs a simple function every 1 millisecond. The body of the function that runs is listView.scrollPosition += 30, which you have likely guessed scrolls (pans) to the right by 30 pixels. And the opposite should obviously happen if the user moves his mouse close to the left edge.

<disclaimer>
I wrote this rather quickly and have not tested it thoroughly. It appears to work well and does not have any significant performance impact (even though the interval is a single millisecond). That said - I would highly encourage you to tweak the numbers and see what works best for you. If you come up with a better combination, please leave a comment below.
</disclaimer>

I hope every is having as much fun with this Windows 8 development as I am!

Happy panning.

Tags:

Windows 8 | JavaScript

Using Promises

by Jeremy Foster 22. June 2012 07:08

If you’re developing Windows 8 apps using JavaScript, then you’re likely familiar with the WinJS.Promise object. You can hardly get by without using one, because a lot of the API in WinJS and WinRT is asynchronous and for JavaScript apps they return a Promise.

I’m going to share with you what I have learned about promises so far in increasing order of sophistication.

Consuming a Promise

Everybody and their uncle is going to use this one. If you need to make a call to WinJS.xhr() for instance, you’re going to get a WinJS.Promise in return. They’re quite easy to deal with actually and you may already know this.

When you get a promise from a method, you simply hang a .then or a .done method off of it and provide a function that you want to run when the asynchronous method is complete.

WinJS.xhr({url:"http://someuri.com/service"})
    .done(function(xhr) {
        //do something here
    });

The call to .xhr comes back really quickly and you and your code go about your day even though the service hasn’t responded yet. Then when the service finally does come back to you, everything inside the done method runs. The promise that .xhr returns contains a payload as well. That’s why we’re able to declare our done function with function(xhr) and then access whatever it is the service returned.

So this is super handy for keeping our UI fast and fluid. But let’s move past merely consuming promises and get a bit more advanced.

Passing a Promise

You’ve seen how to consume a promise so that you can avoid a blocking call to a relatively long running or potentially long running method call. Sometimes you want to write a method yourself that calls an asynchronous method and you want to give your method caller the ability to call it asynchronously.

In this case, all you have to do is return the promise given to you by the asynchronous method you’re calling. So, for example, let’s wrap the example call to .xhr above with our own method call…

function myMethodAsync() {

    //may want to do some stuff here

    return WinJS.xhr({url:"http://someuri.com/service"})
        .done(function(xhr) {
            //do something here
        });
}

There we go. Now I can call myMethodAsync (and by the way, adding Async to the method name is a convention to indicate that it is an asynchronous method) like this…

myMethodAsync()
    .done(function(xhr) {
        // do something here
    });

And notice that I can still specify the xhr parameter for my done function and access the payload.

That’s how we pass along a promise from one asynchronous method to another. Sometimes, however, you need to start from scratch and create your own promise.

Creating a Promise

If I want to create my own method and allow callers to call it asynchronously then I need to return to them a promise. That’s simply the pattern in JavaScript.

Creating a promise is pretty easy, but you need to understand the concept because sometimes things can start to feel messy and it’s really helpful to understand what’s going on (not that I do entirely yet).

In Windows 8 JavaScript development we have the WinJS.Promise. You create it like this…

new WinJS.Promise(function(c,e,p) {
    //function body
});

The c, e, and p are parameters that are themselves functions. Within the function body, then, I can actually call c() when I want to complete the promise, call e() when I want to report an errant case, or call p() when I want to report progress.

Study this method I wrote that makes sure a file exists and if it doesn’t then it creates it…

function assureFileAsync() {
    return new WinJS.Promise(function (c, e, p) {
        if (fileExists("applicationData.json"))
            c();
        else
            appdata.roamingFolder.createFileAsync("applicationData.json")
                .then(function (file) {
                    return Windows.Storage.FileIO.writeTextAsync(
                        file, JSON.stringify(starterData)
                    );
                })
                .done(function () { c(); });
    });
}

There are a few things going on here, so let’s dissect.

First, I did use the Async suffix to indicate to the caller that this is going to be an asynchronous method. I create and return a new WinJS.Promise and the bulk of the logic here exists in the function declaration for that promise.

If a file called “applicationData.json” exists (fileExists is another function I wrote), then we don’t need to do anything and this promise should be considered complete, so we simply call c(). If we wanted our promise to carry a payload (like the xhr method does), then we could put that here by calling c(myResult). In this case, however, we don’t need that.

If the file does not exist, then we want to create it. Notice that this creation is itself an asynchronous call and in the .then there’s even another one. Finally, after we have made certain the file exists and contains my starterData, then we call the c() to indicate that this promise is complete.

There’s plenty more insinuated by this, but I’m going to leave it there for now in the interest of simplicity.

Saving a Promise

Now this trick I just figured out recently and it’s very handy.

Let’s say that in one part of my code I want to do something (call it Action A) that may take some time, and then in another place I want to do something else (call it Action B) but Action B should not occur until Action A has successfully completed.

I could let Action B call Action A asynchronously because then I could hang the .then or .done on that call. Sometimes, though, I don’t want Action B to be the initiator.

Let’s look at a more concrete example. This is the case where I ended up discovering this pattern.

When my application loads I want to load all of the data from file. When you user lands on the home page, I want to show the loaded data. Obviously I can’t show the user the data until it’s loaded, but I want to initiate the data load in the app’s activated event not in the home page.

So here’s what we do. We initiate the data load from the app’s activated event and save the resulting promise somewhere where it will be accessible to the home page. I just added it dynamically onto the WinJS.Application object (not sure if that’s recommended or not, but it works great :) Then from the home page, we simply access that object and hang a .done on it. Easy.

Here’s the data load call from my app activated event…

WinJS.Application.dataLoadedPromise = Data.initializeAsync();

…and here’s where I want to start work on my home page data, but only after the data is loaded…

var hubItemsList = new WinJS.Binding.List();
WinJS.Application.dataLoadedPromise.done(function () {
    getHubItemsAsync()
    ...

Now getHubItemsAsync (itself another asynchronous call, but that’s coincidental) will only get called once the dataLoadedPromise is complete.

Conclusion

There’s much more to promises that I didn’t include here - for brevity in part, but also because I haven’t discovered it yet, but keep an eye on this blog. As I turn over new leaves, I’ll post it here - I promise.

Tags: , , , , , , ,

JavaScript | Windows 8

One Sweet Stack

by Jeremy Foster 21. June 2012 14:36

Following is a mongo post. A huge post. A massive amount of information. The general recommendation is that blog posts should be short, but rules are made to be broken. You can’t tame me. I’m like a wild stallion. So here is a huge blog post.

Last Saturday at the Seattle Code Camp I delivered a presentation I called One Sweet Stack which showed how to start with a SQL Azure database (though it would work with any relational database really), connect to it using Entity Framework, and extend it as OData with WCF Data Services.

I chose this stack because…

  • I come from corporations that have existing database solutions. These aren’t modern, green-field databases of the myriad of flavors. These are classic, tried-and-true, and very much relational. I’m as excited as the next guy all of the modern ways to persist data, but don’t think for a minute that the relational database story is obsolete. Far from it.
  • I love using Entity Framework. I get a little jolt of excitement when I instantiate a DbContext or call SaveChanges(). Geeky? Of course.
  • I think that WCF DS is oft overlooked and recently especially in light of WebAPI (which is also a great product). I’m a fan of designing a database, mapping it through an ORM, and providing an elegant API (whether it’s internal or external) with so little code that I can write it from scratch in a 1 hr session (including explanations).
  • Windows 8 thrills me even more than EF.

I’m hoping to convey virtually all of the content from the presentation here, so it will be a heavy post. Consider it a reference post and come back to it if/when you need it.

The source code for this project is attached. You can find it at the bottom of this post.

First, the database…

So, as I said, I started with a SQL Azure database.

You connect to a SQL Azure database using a regular connection string just like any other database, so it will be a no-brainer for you to read this and apply it to a SQL Server on premises or even a MySQL or an Oracle database.

My database is a simple schema. It’s just a table of a few attractions that one will find on the island of Kauai, Hawaii and one related table of categories those attractions fall into (i.e. waterfall, scenery, flora, etc.). Here’s a diagram…

image

(my diagram by the way was done using asciiflow.com… very geeky indeed)

In the attached zip file, you’ll find KauaiAttractionsAzureScript.sql that you can use to create this database on your own Azure (or local if you’d rather) instance. Just create the database first and then run the script in the context of your new database. If you want to run through this whole exercise connecting to your own database, however, I would highly recommend it. It would be good practice.

Next, setting up the solution…

Follow these mundane steps to get over the snoozer that is creating projects, adding references, and importing packages…

  1. Create a new solution in VS2012
  2. Add a new Windows Class Library using C# (call it SweetStack.Entities)
  3. Add a new WCF Service Application using C# (SweetStack.Service)
  4. Add a new Cloud project using C# (SweetStack.Cloud)
  5. Add a new Unit Test Project using C# (SweetStack.Tests)
  6. Add a new Navigation App for JavaScript Windows Metro style (SweetStack.Metro)
  7. Add a reference to SweetStack.Entities to the .Service and the .Tests projects
  8. Add the .Service project as a web role to the .Cloud project
    1. In the .Cloud project
    2. Right click Roles
    3. Add | Web Role Project in Solution…
    4. Choose the .Service project
  9. Add the latest version of Entity Framework (currently 5.0.0-rc) to the .Entities, .Services, and .Tests projects
  10. Add the latest version of Microsoft.Data.Services (currently 5.0.1) to the .Services project

Next, creating the .Entities project…

We have our database already in place, and now we want to create an Entity Framework context that will allow us to access our database using code.

Instead of creating an EF model (.edmx file), we are going to reverse engineer the database to POCO classes. Why? Because it’s rad. That’s why. First thing you need to do is install the Entity Framework Power Tools Beta 2 (from Tools | Extensions and Updates in VS2012).

Once that is done, you can right click on your .Entities project and choose Entity Framework | Reverse Engineer Code First. Then enter your connection string information. Remember to check the “Remember my password” box so that it will save your credentials into your connection string for later.

So the tooling should have created a bunch of .cs files in your .Entities project. You not only get POCO classes for each of your database tables, you also get one for the context. That’s the one that derives from DbContext. You also get a folder with a map file for each entity.

All of this is beautiful and I’ll tell you why. You now have a direct 1:1 relationship between your code and your database, but you also have the complete freedom to modify the mappings so that the two don’t necessarily match. If your data architect, for instance, called the database table “first_name” and you’d rather that be called FirstName in your code, then just change that property but keep the mapping to “first_name”. You can even ignore certain properties or add new ones that don’t have a mapping. Furthermore, classes that DO have database mappings can be mixed with other classes that do NOT have mappings. It’s all up to you.

Next, let’s test it…

It’s hard to see a Windows class library work without writing a test for it. In the .Tests project write a simple test that looks something like this…

[TestMethod]
public void TestMethod1()
{
    var context = new SweetStack.Entities.Models.KauaiAttractionsContext();
    Assert.IsTrue(context.Attractions.Any());
}

Before you can run the test, copy the <connectionstrings> element from the app.config, create a new app.config in the .Tests project (right click Add New Item…), and then paste the <connectionstrings> element into the app.config for .Tests.

That test should pass if you haven’t mucked anything up already.

Next, time to create the .Service…

This one just FEELS like it’s going to take a while. Low and behold, however, I bet I could do it in less than 37.5 seconds (not that I’ve timed myself). Do this…

  1. Delete (from the .Service project) the IService1.cs and Service1.cs files that you got for free (even though you didn’t ask for them :)
  2. Right click the .Service project and add a new item… add a WCF Data Service called Entities.svc
  3. Once your file is created, check out the class name and see how it derives from DataService<T> but the T is undefined. Fill that in with SweetStack.Entities.Models.KauaiAttractionsContext
  4. Now uncomment the line in the InitializeService method that says SetEntitySetAccessRule and in the quotes just specify an asterisk (“*”). You can change the EntitySetRights.AllRead to .All if you like, but we won’t be writing any data in this tutorial anyway, so it doesn’t matter so much.
  5. Copy the <connectionstrings> element from the app.config of the .Entities project into the web.config of your .Service project
  6. Put your hands down… you’re done!

Set your .Service project to the startup project and run it. You should get a browser that looks like this…

image

Note: if you get a list of files instead, just click on the Entities.svc first.

Next, we let’s see what we’ve got…

What you’re looking at there is a GEN-YOU-WINE OData feed. That’s exciting. OData rocks. Not only do you get all of your entities extended through OData, but you get type information about them and you get their relationships with each other. Also, you can ask an OData feed for XML or for JSON and it will say “Yes, sir/ma’am.”

Fire up Fiddler and hit that service root URL appending each of the following and see what you get for responses (also add “Accept: application/json;odata=verbose” to the headers in Fiddler to request JSON). Issue the following commands against your service and behold the results…

{root service URL}?$top=1 selects just the first entity.
{root service URL}?$select=Id,Name fetches all entities, but projects them to lighter JSON objects by only including the Id and Name properties.
{root service URL}?$filter=Location%20eq%20'North' gives you entitites that have a Location value of “North”.
{root service URL}?$filter=substringof('Falls',Name)%20eq%20true” gives you only entites with the word “Falls” in their Name
{root service URL}?$select=Name&$orderby=Name selects just the Name property and sorts it
{root service URL}?$expand=Category this one brings in the related Category entity… this a significant point and a differentiator from flat GET web service operations. Look at the JSON message in the response with and without this URL property.

If that doesn’t turn your crank then you should check your Geek card… it might be expired.

Next, we go Metro…

We’re ready to consume our data. We’re going to be working here with an HTML/JS Metro application which makes it reasonable brainless to consume JSON. Here we go…

I had you create your Metro app from the navigation template, so you should have a pages folder (assuming your using Visual Studio 2012 as opposed to Visual Studio 11). In there you have home.html, home.css, and home.js. Those three files are all we’re going to concern ourselves with for now.

In the .html file, you need to create a ListView and define an item template and a header template (because we want our items to appear in groups). Here’s what that would look like…

<div id="itemtemplate" data-win-control="WinJS.Binding.Template">
    <div data-win-bind="onclick:click">
        <img data-win-bind="src:ImageUrl" />
        <div data-win-bind="innerText:Name"></div>
    </div>
</div>
<div id="headertemplate" data-win-control="WinJS.Binding.Template">
    <div data-win-bind="innerText:category"></div>
</div>
<div id="list" data-win-control="WinJS.UI.ListView"></div>

Then in the .css file add the following so that our images are the right size and our ListView is tall enough to show two rows…

.homepage section[role=main] {
    margin-left: 120px;
}

.homepage #list {
    height: 100%;
}

    .homepage #list img {
        width: 280px;
        height: 210px;
    }

Finally, in the .js file we need to add just a little bit of code. I’ll just drop it all on you and then explain each section. Put this inside the page’s ready method…

var attractionsListGrouped = new WinJS.Binding.List().createGrouped(
    function (i) { return i.Category.Name; },
    function (i) { return { category: i.Category.Name }; }
);

var list = document.querySelector("#list").winControl;
list.itemDataSource = attractionsListGrouped.dataSource;
list.itemTemplate = document.querySelector("#itemtemplate");
list.groupDataSource = attractionsListGrouped.groups.dataSource;
list.groupHeaderTemplate = document.querySelector("#headertemplate");
            
WinJS.xhr({
    url: "http://onesweetstack.cloudapp.net/Entities.svc/Attractions?$expand=Category",
    headers: {"Accept":"application/json;odata=verbose"}
    }).then(function(xhr) {
        JSON.parse(xhr.response).d.forEach(function (i) {
            i.click = function (args) { WinJS.Navigation.navigate("/pages/attraction/attraction.html", i); }
            i.click.supportedForProcessing = true;
            attractionsListGrouped.push(i);
        });
    });

The first part (var attractionsListGrouped…) creates a new WinJS.Binding.List that groups the items by their .Category.Name. This necessitates that we bring our Attraction entities down with that $expand property included to get the related Category, but that’s easy so we worry not.

The next part imperatively sets the item and header templates and the data sources of both the items and the groups. This can be done before our list has even been populated with any items. In fact, we need to do it that way because the call we make to get the items is asynchronous and we need that list that we’re binding to to exist before we even get back from that call.

The last part is the xhr call. You can see the syntax. The xhr expects an object within which we’re specifying the url and a custom header. The function we pass in to the subsequent .then is going to run after we get back from the xhr call. At that point, we can look at the response, parse it as JSON, and then for each item, push it into our list. This list is a WinJS.Binding.List which means that it is essentially observable and will tell the UI when updates have been made so it can change accordingly. So when our items are fetched and filled in, the user will see them pop into the ListView in his view.

Tangent about application/JSON;odata=verbose…

Remember how we added application/JSON;odata=verbose to our headers for the xhr call? Why would we do that? It’s because we’re using the prerelease version of WCF DS, and the existing OData JSON syntax has been dubbed “verbose” to make room for some awesome new methods for expressing rich, typed, interrelated OData while keeping the payload light, light, light. More on that at a later time.

Conclusion

Attached you’ll find the complete source code. Hope it helps you learn Windows 8 development and I hope you get your first app done soon and are rewarded with huge royalty checks :)

And that does it for this walk through. It was a marathon post, so if you’re read this far email me your mailing address and I’ll send you a gift in the mail. I’m betting I won’t be troubled to send too many gifts :) (offer expires the end of June 2012)

OneSweetStackLive.zip (9.90 mb)

Tags: , , , , , , , , , , , , , , ,

C# | CSS | JavaScript | Visual Studio | Windows 8

Page Navigation in Windows 8 JavaScript Apps

by Jeremy Foster 21. June 2012 12:31

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…

Performing a top-level navigation.

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…

Navigating to page2.html the recommended way.

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.
    image
  2. Reference the navigate.js from your default.html file…
    image
  3. Add a contenthost to your default.html file
    image

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&$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 a function to 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.

Tags:

Windows 8 | JavaScript

Fast Refresh... Nugget!

by Jeremy Foster 18. June 2012 14:59

imageHey, Metro developers, if you’re using HTML/JS to build your apps, I have a little golden nugget for you. Actually, it’s possible you already know and I’m the one that’s late to the game. Anyway, have you ever made a little tiny tweak to your HTML structure, a slight mod to your CSS style, or a little enhancement to your JavaScript and wanted to see the change effect immediately instead of relaunching your app each time? It’s a valid desire. My last job was website development and so I’m used to the whole save, switch, refresh workflow.

If you’re working without the debugger attached, then you know it’s not that difficult, you just hit CTRL + F5 again.

If you are working with the debugger attached, however, you might think you have to stop (SHIFT + F5) and then start again (F5). Actually, though, all you have to do is hit F4 (Fast Refresh is how we call that)! Now that’s handy!

Tags:

JavaScript | Windows 8

A Metro Netflix Browser in HTML/JS - The Hub Page

by Jeremy Foster 13. June 2012 12:18

A previous post illustrated how to call into the Netflix API to create a quick and dirty grid of movies with data from Netflix.

Well, that version landed during the CP version of Windows 8 and before a lot of other little things I’ve learned about the platform, so I’ve been meaning to improve it for some time, and now is that time. Let’s do this…

Discovery

Any time you’re planning to utilize a public API like this, you might want to spend some time in discovery. Check the documentation, hit the API, look at the results, and overall just get a really good idea of what you’re looking at so you don’t waste time doing it while you’re writing your code.

Let’s do some discovery, then of Netflix’s API.

Some companies have a link for developers available on their public portal. There’s nothing like that on Netflix’s site though. The next obvious thing to do is Bing it. A search for netflix developer api brings up some good results. The first takes us to developer.netflix.com. This is a well made portal for developers and does a good job of informing us what we have to work with. On the documentation page, you can see that there is a JavaScript API and a REST API. Either of those would likely work, but I’m in love with OData, and if you look a bit further down that page you’ll see that they have an OData Catalog in beta. That’s what I want to use. OData rocks because you get typed and interrelated entities with a common query URL language that various clients have been created for. But you can also just hit it sans client with HTTP calls and you can request a JSON response instead of the default XML if that’s what you’re into… and that’s exactly what I’m into!

The catalog is at odata.netflix.com/catalog. Let’s make like dudes and skip the manual and just jump right in. I’ll open Fiddler up. If you’re using Google Chrome, you can use the Dev Http Client app to do something similar. In Fiddler, I’ll go to the Composer tab and add http://odata.netflix.com/catalog for the GET request and hit Execute. The body of the response that I get back is like this…

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<service xml:base="http://odata.netflix.com/v2/Catalog/"
    xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:app="http://www.w3.org/2007/app"
    xmlns="http://www.w3.org/2007/app">
  <workspace>
    <atom:title>Default</atom:title>
    <collection href="Genres">
      <atom:title>Genres</atom:title>
    </collection>
    <collection href="Titles">
      <atom:title>Titles</atom:title>
    </collection>
    <collection href="TitleAudioFormats">
      <atom:title>TitleAudioFormats</atom:title>
    </collection>
    <collection href="TitleAwards">
      <atom:title>TitleAwards</atom:title>
    </collection>
    <collection href="People">
      <atom:title>People</atom:title>
    </collection>
    <collection href="TitleScreenFormats">
      <atom:title>TitleScreenFormats</atom:title>
    </collection>
    <collection href="Languages">
      <atom:title>Languages</atom:title>
    </collection>
  </workspace>
</service>

That’s what the primary endpoint of an OData feed always looks like. It tells us what entities we are dealing with. You might expect to see a Movies entity here, but in fact it’s called Titles. Now all we have to do to access the Titles is change our request from http://odata.netflix.com/catalog to http://odata.netflix.com/catalog/Titles.

Doing so and hitting Execute comes back with a 3,383,106-byte reponse! That’s because we’ve just request ALL of Netflix movies.

Let’s do a couple of things here. First, let’s request it in JSON and see what the size is. There are two ways (that I know of) to request a JSON response. We can either add $format=json as a URL parameter, or we can add Accept: application/json to the request headers. I’ll do the latter so as not to clog up my URL. So here’s what my request in Fiddler is looking like…

image

Execute that and you’ll see that our response size is down from 3,383,106 to 1,852,565! Awesome. That’s why I’m into JSON. And it will be smaller still once it implements JSON Light (more on that later). Not only are there a lot of Titles in this response, but there are a lot of properties per Title. Double click on the response (in the left pane of Fiddler) and look at the raw results (in the right pane) and see how many properties each title has. It’s a lot, and most of those are deferred properties which means that they are themselves typed entities containing a rich set of properties and we haven’t even pulled that data down yet!

Well, let’s make our payload reasonable first of all by just grabbing the first 10 titles. You would do that by using http://odata.netflix.com/catalog/Titles?$top=10. Now we’re pretty small, so we can afford to get some of this deferred data. Let’s issue this http://odata.netflix.com/catalog/Titles?$top=10&$expand=Cast, and see what you get. Notice the Cast is not longer deferred, but it has fetched all of the cast members of the title (don’t look at the first one… it doesn’t have any cast).

There’s just a ton more that I could show you about interacting with this OData feed, but you should just check out http://www.odata.org to get your information from the source. It’s a ton of fun and really powerful, but we have an app to write.

 

Writing our Metro app…

Now that we’re pros at fetching Netflix data, let’s do something with it. In my last Netflix post I started with the Grid Application, but this time I’m going to start with blank… actually, I’ll want the navigation functionality too, so fire up Visual Studio 2012 and start the Navigation App template…

image

In case you haven’t seen this template before, this is just the blank template but with the recommended navigation pattern for apps already implemented. So you get the navigator.js file (under the js folder) and you get the pages folder with the home page already in there for you. That’s where we’ll start.

Before we begin though, I want to add a helper function that tends to make my life easier. Paste the following into the default.js file after the modular function so that it’s in the global namespace…

function q(query, context) {
    context = context || document;
    var result = context.querySelectorAll(query);
    if (result.length > 1) return Array.prototype.slice.call(result);
    else if (result.length == 1) return result[0];
    else return null;
}

Now for query selections, we can just do something like q(“#myelementid”).

Now open home.html, home.js, and home.css. We’re going to be in those three file for a while.

In home.js, add the following to the ready function…

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

That sets up the observable list that we’re going to be putting our movies in after they’re fetched. We want to create it right away because we’re going to bind to it even before there are any movies in it. Actually, we won’t use the titlesList, but only the titlesListGrouped since we will want our movies to be grouped. This can be set up before we even have any data in it because it’s just a definition of the functions that are necessary for fetching groups.

Then we’re ready to do our call to the API, so add this…

WinJS.xhr({
    url: "http://odata.netflix.com/Catalog/Titles?$format=json&$top=200"
    }).then(function (xhr) {
        //code goes here
    });

This is going to get the first 200 movies. The .then method gives us a chance to capture the response (that’s the xhr parameter) and declare a function to execute when the call has come back. The code that we add inside that function may run 50 milliseconds after the call or it may run 10 seconds later, but either way, we’ve called it asynchronously so we’re not going to block the UI thread.

Now add this inside that .then function…

var titles = JSON.parse(xhr.response).d;
titles.forEach(function (i) {
    titlesList.push({
        title: i.ShortName,
        imageUrl: i.BoxArt.LargeUrl
    });
});

This is going to take some dissection because a lot is happening in a few short lines. First, JSON.parse turns the xhr.response from a string into a JavaScript object. Next, JSON Verbose format wraps results in a d property, so we need to access d and should expect it to contain the array of titles. Next, we are iterating that list of titles and for each one, we are pushing an anonymous object containing title and imageUrl into our list. We’re doing this because we don’t want the whole gigantic object that Netflix sends us, so we project it to a smaller, simpler object that contains all we need for now.

Next, we need to tie our binding list to the list view on the HTML page and tell it where to find its template and all that. So just add this code (just below the last code you entered)…

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

Well, that’s the guts of it. Here’s what you should have for your 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) {
            
            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&$top=200"
            }).then(function (xhr) {
                    var titles = JSON.parse(xhr.response).d;
                    titles.forEach(function (i) {
                        titlesListGrouped.push({
                            title: i.ShortName,
                            imageUrl: i.BoxArt.LargeUrl
                        });
                    });
                });

        }
    });
})();

Now, in our home.html, we’ll need to declare the template for the headers, the template for the items, and we’ll also need to declare the list itself. Here’s what all of that looks like. Add this inside the section labelled Main content

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

The header template and template or of type WinJS.Binding.Template and the list is of type WinJS.UI.ListView. Notice also, that inside our templates, we can use data-win-bind to bind element attributes to data properties.

You should be able to run your app at this point and get something that works. If you run into any trouble, you can either look through the steps again to see if you missed anything, or you could use a file compare tool to compare what you have to the attached project. It would be good practice for you to fix it manually. I always learn a lot that way.

The last thing we’ll do for this is add just one style to make everything look a bit better. If you add the following to your home.css file, then the list will automatically show two rows of data which will look much better.

.homepage #list {
    height:100%;
}

Notice that I’ve prefixed my #list with the .homepage class. This is because CSS style rules aren’t scoped like the JavaScript functions are, so you always have to specify the fully qualified names. If you don’t, then an element with the id list on another page could get this style rule applied as well.

There you have it. I’ll call this “Stage 1” and attempt to blog about adding the section and detail pages later. Here’s what your app should look like at this point though…

Screenshot (9)

You can download source code for the entire project here: NetflixBrowser.zip (12.48 kb).

 

Tags:

Windows 8

How to do Semantic Zoom in an HTML/JS App

by Jeremy Foster 13. June 2012 10:17

Semantic Zoom is super easy, but even the easy things can use some conceptual explanation and examples to clarify them. Rest assured that once you see it, you’ll go “Ah! That won’t be a problem then.”

If you use XAML/C# to make your Metro apps, then you should check out Jerry Nixon's post on semantic zoom.

So, I’m going to be talking about Semantic Zoom. You know what that is right? It’s different from optical zoom. It’s a Windows 8 differentiator and it’s really helpful. It’s a way of zooming out of some information and making it easier to orient and easier to consume. Optical zoom just scales everything. Semantic zoom shows a different logical version of the same list.

Any given list in a Windows 8 screen may be 3 or 4 or 5 screens worth of horizontal information, right? Well, it’s not hard to pan that far, but it’s not always easy to really see what your scope is when it’s on 4 screens. When a user semantically zooms out, he is hoping to get oriented with your data. He is hoping to rise up so he can understand and/or so he can dive back in at just the right place.

I’m going to provide an example here. My example is a list of attractions in Kauai. Each has a category property - things like Flora, Scenery, Waterfall, etc. I will use these categories to group my list, but with the grouping and all of the content I want to show, the list is about 4 screens wide…

image

This might be a good scope of data for this view in my app, but at the same time it might be too much to expect a user to be able to consume in a glance. So, we implement semantic zoom. When the user pinch zooms, we want to show them something like this…

image

This is not very stylish, I know, but it serves to make the point. We want to indicate in much less horizontal space (and hopefully on a single screen) what our data contains. In this case, we’re showing the categories. We could get quite creative with what we show here. The concept is to logically expand our scope to orient the user.

Now when the user chooses the Waterfall tile, he’ll be semantically zoomed back in and will be taken directly to the waterfall section. The user can also zoom back in using a stretch zoom gesture (two fingers on the screen and then moved further apart).

Let’s move on to how to implement this. It’s by no means rocket science. Unless of course you’re building an app for… er… rocket science.

Start off with a blank Metro application. First thing you’re going to need is the data.

In your default.js file, add an onready function like this…

app.onready = function (args) {
    
};

And then inside of it add your data like this…

var attractions = [
    { name: "Fern Grotto", category: "Flora", location: "East", imageUrl: "http://www.kauai.com/photos/kauai/point/98/super/fern_grotto-kauai-attraction.JPG", description: "Only accessible by boat or Kayak, the fern Grotto is located about two miles up Kauai’s Wailua River, the only navigable river in the State of Hawaii." },
    { name: "Hanalei Valley Lookout", category: "Scenery", location: "North", imageUrl: "http://www.kauai.com/photos/kauai/point/51/super/hanalei-valley-lookout-kauai-attractions-3.jpg", description: "The Hanalei Valley is an enchanted site charmed with the likes of countless waterfalls, rainbows, fields of taro and hidden treasures waiting to be explored." },
    { name: "Hanapepe Swinging Bridge", category: "Other", location: "West", imageUrl: "http://www.kauai.com/photos/kauai/point/93/super/843726541306971801.jpg", description: "Located in old town Hananpepe a Historical sight made up of an eclectic group of galleries and shops. Home to Friday night Art walk." },
    { name: "Kalalau Lookout", category: "Scenery", location: "West", imageUrl: "http://www.kauai.com/photos/kauai/point/94/super/3075381091306977440.jpg", description: "The Kalalau lookout stands at 4,00 feet above sea level and gives you a peek at a valley that as late as the 1920's still was the home to residents who farmed crops there. The only way into the valley is by foot along the Kalalau Trail or by boat." },
    { name: "Kauai Coastal Path", category: "Coastline", location: "East", imageUrl: "http://www.kauai.com/photos/kauai/point/100/super/kauai-coastal-path-kauai-attractions.JPG", description: "Kauai Coastal Path is a scenic and and safe place to walk, run or bike while taking in the beautiful scenery of Kauai's East Side." },
    { name: "Keahua Arboretum", category: "Flora", location: "East", imageUrl: "http://www.kauai.com/photos/kauai/point/95/super/keahua-arboretum-kauai-attractions-5.JPG", description: "The Keahua Arboretum is planted with native and introduced plants by the University of Hawaii and is used as an outdoor classroom to students and visitors. Cool off in the cold mountain spring water and enjoy lunch at one of the picnic sites." },
    { name: "Kilauea Lighthouse National Wildlife Preserve", category: "Coastline", location: "North", imageUrl: "http://www.kauai.com/photos/kauai/point/49/super/kilauea_lighthouse_national_wildlife_preserve-kauai-attraction.JPG", description: "Kilauea Point National Wildlife Refuge started in 1985 by the U.S. Fish and Wildlife Service is marked by its towering lighthouse. The ocean cliffs and tall grassy slopes of a dormant volcano provide a protective breeding ground for many Hawaiian seabirds" },
    { name: "Koloa Landing", category: "Coastline", location: "South", imageUrl: "http://www.kauai.com/photos/kauai/point/99/super/koloa-landing-kauai-attractions-2.jpg", description: "Once one of the largest deep water whaling ports in Hawaii, Koloa Landing is now a popular location for shore dives." },
    { name: "Lawai International Center", category: "Other", location: "South", imageUrl: "http://www.kauai.com/photos/kauai/point/110/super/lawai-international-center-kauai-attractions.JPG", description: "Lawai International Center and the 88 Shrines are located on the ancient site of Heiau where Hawaiians once came for healing." },
    { name: "Menehune Fishpond", category: "Other", location: "East", imageUrl: "http://www.kauai.com/photos/kauai/point/48/super/menehune-fishpond-kauai-attractions.JPG", description: "Menehune Fish Pond is located just above the Nawiliwili Harbor. The Menuhune Fish Pond, Alekoko got it's name from the legend that a small race of people known as menehune built these ponds 1,000 years ago overnight." },
    { name: "Napali Coast", category: "Coastline", location: "North", imageUrl: "http://www.kauai.com/photos/kauai/point/82/super/napali-coast-kauai-attractions.jpg", description: "The Napali is a fifteen mile stretch of coastline starting on the north shore at Kee beach and ending on the west side at Polihale beach. This rugged coast will leave you breathless as you gaze upon the he razor sharp cliffs that rise sharply from sea to " },
    { name: "Opaekaa Falls", category: "Waterfall", location: "East", imageUrl: "http://www.kauai.com/photos/kauai/point/88/super/opaekaa_falls-kauai-attraction.JPG", description: "Opaekaa Falls can be seen from the scenic lookout along Kuamoo Road in the Wailua Homesteads. " },
    { name: "Spouting Horn", category: "Coastline", location: "South", imageUrl: "http://www.kauai.com/photos/kauai/point/86/super/spouting-horn-kauai-attractions-1.JPG", description: "Spouting Horn Beach Park is a delightful lookout where you can watch a blowhole spout a plume of sea water into the air." },
    { name: "Tree Tunnel", category: "Flora", location: "South", imageUrl: "http://www.kauai.com/photos/kauai/point/91/super/tree-tunnel-kauai-attractions.JPG", description: "The beautiful canopy of eucalyptus trees line Maliuhi Road, the gateway to Kauai's sunny side and the towns of Koloa, and Poipu." },
    { name: "Wailua Falls", category: "Waterfall", location: "East", imageUrl: "http://www.kauai.com/photos/kauai/point/50/super/wailua_falls-kauai-attraction.JPG", description: "This 140 foot waterfall appears on many postcards, print and media collections and was used as the opening scene for the 1970’s Television series Fantasy Island." },
    { name: "Waimea Canyon", category: "Other", location: "West", imageUrl: "http://www.kauai.com/photos/kauai/point/83/super/waimea-canyon-kauai-attractions-2.JPG", description: "Waimea Canyon State Park is the largest canyon in the Pacific and will undoubtedly capture your gaze, with its 10 mile long stretch at a mile wide and measuring more than 3,500 feet deep." },
    { name: "Wet and Dry Caves", category: "Other", location: "North", imageUrl: "http://www.kauai.com/photos/kauai/point/111/super/wet-and-dry-caves-kauai-attractions.jpg", description: "Waikanaloa & Waikapalae Wet Caves are located off the the main road in the Haena State Park and are easy to get to. The Waikanaloa Cave is not for swimming. The Waikapale cave is located a a little further up the road and involves a quick hike to the swim" },
];

And then you need to turn that simple JavaScript array into a Binding List so you can bind to it. Like this…

var attractionsList = new WinJS.Binding.List(attractions);

And then you group that list like this…

var attractionsListGrouped = attractionsList.createGrouped(
    function (i) { return i.category; }, //group key
    function (i) { return { category: i.category }; }  //group
);

And there’s that.

Now, let’s visit your HTML file (default.html).

You’ll need your actual ListView…

<div id="zoomedinlist" data-win-control="WinJS.UI.ListView"></div>

And you’ll also need a template and a header template…

<div id="headertemplate" data-win-control="WinJS.Binding.Template">
    <div data-win-bind="innerText:category"></div>
</div>
<div id="zoomedintemplate" data-win-control="WinJS.Binding.Template">
    <div>
        <img class="item-image" data-win-bind="src:imageUrl" />
        <div data-win-bind="innerText:name"></div>
    </div>
</div>

And then you need to bind the ListView to your data, so go back to your default.js file and after the var attractionsListGrouped statement, add this…

var zin = q("#zoomedinlist").winControl;
zin.itemDataSource = attractionsListGrouped.dataSource;
zin.groupDataSource = attractionsListGrouped.groups.dataSource;
zin.itemTemplate = q("#zoomedintemplate");
zin.groupHeaderTemplate = q("#headertemplate");

Now you should have a working list, and all we have to do is add the semantically zoomed out version and the semantic zoom control itself.

So, on the default.html page, add the semantic zoom control and the zoomedoutlist to the list you already have like this…

<div data-win-control="WinJS.UI.SemanticZoom">
    <div id="zoomedinlist" data-win-control="WinJS.UI.ListView"></div>
    <div id="zoomedoutlist" data-win-control="WinJS.UI.ListView"></div>
</div>

(note that last code should be pasted over the existing zoomedinlist since we already had that there)

Then, that zoomedoutlist needs some data binding, so we go back to the default.js and add this…

var zout = q("#zoomedoutlist").winControl;
zout.itemDataSource = attractionsListGrouped.groups.dataSource;
zout.itemTemplate = q("#zoomedouttemplate");

OKAY STOP. Let me explain what’s going on here. Quite simply, we’re just adding two different ListView controls with their own data bindings (that happen to be based on the same data, and then we are wrapping both of those up with the WinJS.UI.SemanticZoom control.

Keep in mind, that there are no constraints necessarily on what can comprise those two lists. You, the developer, are responsible for making sure that your semantic zoom control makes good sense for the user.

Now, please notice that the data source for the zoomed in list is a grouped list of attractions, while the data source for the zoomed out list is a list of groups. Thanks why we get the categories for our zoomed out tiles.

I added a couple of classes in the templates that I had you paste into your HTML, so if you add the following style rules to your default.css file, then that should make everything look sensible…

.item-image {
    width: 280px;
    height: 210px;
}

.sz-category {
    width: 200px;
    height: 200px;
    background-color: green;
    color: white;
    font-weight:bold;
    font-size: large;
    padding: 10px;
}

And that should do it. Leave a comment if this was helpful. Actually, leave a comment if it wasn’t helpful too. :)

Happy zooming.

Tags: , , , , , , , , , , , , , , , ,

CSS | HTML | JavaScript | Windows 8

Styling the ListView

by Jeremy Foster 13. June 2012 08:56

I just read a great article in the Windows Dev Center and must share. If your making a Metro app using JavaScript and you are using a ListView control, this is essential information.

The ListView acts as a grid or a list. In XAML, there is a GridView and a ListView, but in HTML/JS the WinJS.UI.ListView serves both roles. If you want to make something like the tiles in the default grid application, you’ll need the ListView, and if you want a simple vertical repeater, you’ll use the ListView.

If you want to style the ListView, you will do so by overriding or appending CSS properties in style rules that are based on various CSS classes. Many of the classes that you might need to override are detailed and illustrated in this excellent article in the Windows Dev Center - Styling the ListView and its items.

Illustrations like the following are extremely helpful in determining what part of the ListView I want to style…

The primary components of a ListView

The article explains, for instance, what to do if you want to add a graphic to the surface of the ListView that pans out of view with the other items when the user swipes. In that case you would add the graphic to the win-surface. If you want the graphic to stick in place as the user pans the ListView’s items past it, then you would add the graphic to the win-listview class.

A ListView with a border and a background image

A graphic added to the win-listview will stay in place as the user pans items in front of it.

A ListView that has a styled surface

A graphic added to the win-surface will pan out of view along with the items.

Gems like this are why I think the dev.windows.com documentation is extremely helpful when coming up to speed on Metro app development. There’s so much content in there though that sometimes it’s hard to know what you are missing.

Keep an eye on my blog, and I’ll surface the gems for you.

Tags:

Windows 8 | CSS

When to Use ViewBoxes and FlexBoxes

by Jeremy Foster 12. June 2012 12:11

HTML and CSS is great, but there’s at least one thing that has driven web designers mad for ages - layout. We used to use tables and it worked. We knew their weaknesses, but they worked. Then we were told that tables are for tabular data and div elements are for layout, but divs are wretched creatures. To set divs next to each other one had to float them, but then when finished floating had to be explicitly turned off - argh. Also, divs had no notion of filling vertical space or of controlling the vertical placement of anything within it.

So a myriad of web designers resorted to absolute positioning, browser hacks, jQuery UI positioning, or some other means just to get things to go where they ought.

Enter Windows 8.

Windows 8 allows us to design our Metro style apps using HTML and CSS. In doing so, however, it the CSS standards and Microsoft have given us some facilities to finally place things where we want them.

It’s not obvious how everything works though so let me give you a boost. If you start with a Fixed Layout Application (for the record, I think it should be called the Flexible Layout Application) project template you get the right stuff automatically, but here’s an explanation so you have the concept as well.

We’re dealing with two entities here: the WinJS.UI.ViewBox control and the -ms-flexbox css property value (for the display property).

WinJS.UI.ViewBox

The purpose of the ViewBox is stated in the documentation. It says that it “Scales a single child element to fill the available space without resizing it. This control reacts to changes in the size of the container as well as changes in size of the child element. For example, a media query may result in a change in aspect ratio.”

The first thing I had a hard time wrapping my head around was the overlap between a ViewBox and a FlexBox. Then I discovered that there really isn’t any. The ViewBox control is quite simple. It scales the content that it contains but maintains it’s aspect ratio.

It works like this…

image

Note that it does not work like this…

image

In other words, as it says in the documentation, it scales the contents, but it keeps their proportions.

And that’s really the end of it. The ViewBox serves this one purpose.

Flexbox

Now it’s time to talk about the flexbox. This is not a WinJS control, but rather an implementation of a CSS3 property. It’s not quite a standard property yet because all of the browsers are still implementing it with vendor specific properties and values, but it’s close. For Windows 8, we specify a display property with a value of -ms-flexbox to indicate flexbox layout.

The purpose and scope of the flexbox is a bit bigger than the ViewBox. Here’s what the W3C spec for the CSS Flexible Box Layout Module says “In the flexbox layout model, the children of a flexbox can be laid out in any direction, and can "flex" their sizes, either growing to fill unused space or shrinking to avoid overflowing the parent. Both horizontal and vertical alignment of the children can be easily manipulated. Nesting of these boxes (horizontal inside vertical, or vertical inside horizontal) can be used to build layouts in two dimensions.”

So, like the ViewBox, we still have the concept of the container’s content changing in size to fit the container, but this has more to do with a collection of child items.

Additionally, the flexbox offers a lot of properties to specify how it’s children are laid out. A quick glance in Blend at the CSS properties on a div in the Flexbox category will enumerate them for you…

image

Notice first the -ms vendor specific prefix as I mentioned.

To give a thorough description of the possibilities with these properties, I’d be duplicating what’s already done quite nicely on the flexbox page on w3.org, so just go there and read the nitty, gritty detail.

Differences

The ViewBox is a WinJS control, whereas the flexbox is a CSS property.

The ViewBox always acts on a single child item, but the flexbox can act on multiple child items.

The ViewBox itself changes size to fit it’s container as a core feature. The flexbox can be told to scale to 100% either in width or height, but it doesn’t have to.

The ViewBox does not extend control over the alignment and scale modes of it’s contents, but always does the same thing - scales the child item without changing it’s proportion.

All Together Now

Now that you know how different these controls are, consider them together. If you put a flexbox div inside of a ViewBox, you get a really effective layout tool. Try this for your HTML…

<body>
    <div data-win-control="WinJS.UI.ViewBox">
        <div class="flexy">
            <div class="item">A</div>
            <div class="item">B</div>
            <div class="item">C</div>
        </div>
    </div>
</body>

With this as the CSS…

.flexy {
    -ms-flex-align: center;
    -ms-flex-direction: column;
    -ms-flex-pack: center;
    display: -ms-flexbox;
}

.item {
    height: 200px;
    width: 200px;
    border:solid 1px;
    font-size:9em;
}

What you have now is a flexbox that fills its area well. Look at these simulator screenshots so you can see what this would look like…

imageimageimageimage

XAML is unarguably the most powerful layout engine I’ve ever seen, but I really don’t feel like there’s too much in HTML/CSS that we’re missing now with additions like this. It’s rather empowering.

Happy layouts!

Tags: , , , , , , , , , ,

CSS | Windows 8

Feed Subscribe