forge

Working with the Windows 8 Visual Studio JavaScript Grid App – Part 1 – Data and Navigation

I’ve been working on learning Windows 8 application development and I’ve been struggling to get my head wrapped around some of the pieces, so I wanted to document some of the key pieces that I’ve learned about the Grid App template so far. Let’s start with Data.

Data.Js

The data model that’s a part of the template is crazy. It’s static initialization inside of the /js/data.js file I wanted to eliminate that and make it read from a data file. The idea here is that I can get quite a bit of what needs to be localized into a single file that will be easy (ish) to localize. To do that I replaced the call generateSampleData().forEach(function (item) { list.push(item); }; with my own generateData() method. It’s the second method in the following image:

OK, so in this case I’m deploying the data file in a /data folder and it is called menu.data. I load it by using the Windows.Storage.FileIO API. Once I have it I parse it with JSON.parse() then I iterate each item grab the group item, stuff a link into the items list and I add the rest of the URL for the background image. I push that to the list that was defined above. The helper function above generateData() just locates the group. Yea, resolveGroupReference() is very similar, however, it expects that the groups are on items already.

The data file itself isn’t that bad – except that you have to deal with the fact that JSON.parse() is really particular about what it gets in. It has to have the keys quoted it gets upset at extra whitespace between the colon and the value, etc. Take a look at my simple sample file:

You’ll see the quoted values, and if you look to the far right you’ll see a new key/value for page which is the URL for the page to load for the item. The out of the box grid app expects every item loads the same detail page – and every group loads the same page. I didn’t want that. I wanted each item to be able to load its own page, thus adding the URL to the object. You’ll also notice that my object has a .groups and a .items – The code above in generateData() and getGroupObject() just stiches the groups into the items like the data expects.

Note: I know this is a stupid/silly way to do the groups now, I’ve just not gone back and fixed it since doing so was more of an architectural change than I was comfortable making. If you do this you’ll want to manage this slightly differently and stuff the data for groups into a different list rather than doing the silly mapping that the Grid app does.

The final thing is that the way the grid app is created it automatically sorts groups based on the key so I just prefixed the key to get the order I wanted. I could change the compare function, but I was lazy.

groupedItems.html

The application starts with default.html but the control on default.html loads a Application.PageControlNavigator that loads HTML fragments into the page for you. The data-win-options sets the parameter for the PageControlNavigator so that it’s home is /pages/groupedItems/groupedItems.html to be loaded in. That page has a few key pieces which I’ll explain after the screen shot.

OK, in this. The key is actually at the bottom. The last DIV tag is really a WinJS.UI.ListView – which the code will stitch together with the data model to make everything get displayed. The first two DIVs are templates that ListView will use. One key thing to note is that the group header (in the header template) is defined as a button – and it has a button handler. This will be important as we talk about navigation.

groupedItems.js

The way that the navigation and fragment pages work is that you do a WinJS.UI.Pages.Define and provide the URL of the page plus a collection of items to tie to the page. These are mostly event handlers and call backs that can be used from outside the page. The ready property/method/delegate will be called by the framework when the fragment is loaded and ready to go. This starts by binding the ListView control to its templates and defining a handler _itemInvoked:

Later this method calls this._initializeLayout(), this method actually binds the data source:

This is does something crazy. If the application is in a snapped state (think side-by-side – it’s not full screen) then it loads the groups into the item template and blanks out the group data source. The effect of this is that the groups become items. In the normal case the headers are loaded as the groups and the items are loaded. This all got crazy when I started looking at _itemInvoked:

Looking at this code you can clearly see that sometimes it treats an item like a group and othertimes like an item. This doesn’t make sense unless you see that they start treating groups like items in _initializeLayout. So in order to get the navigation to use my pages that are a part of the objects now I need to go update the button event handler like so:

The commented out line is the original and the two lines that follow are me getting the group (instead of just the key) so I can get the page off of it. Next is the _itemInvoked:

Here you’re seeing the behaviors I want. I get the item out of the groups and navigate to it by calling navigateToGroup – which I updated above, and for items I get the item then navigate to the page attached to that data.

Whew!

Wow, untangling the pieces of this to get it to a working structure that I can use to nave my data initialized and to be able to navigate was quite the challenge. Next up is starting to implement some of the other features. I’ll let you know how that goes.