forge

Working with Settings Pages in Windows 8 JavaScript Applications

Adding additional page fragments to be navigated to in the grid application is relatively straight forward, just select the Page Control new item and start modifying the code. However, while this works well for page fragments for the application, it doesn’t work all that well for settings pages. In Windows 8 you’re supposed to leverage the existing Settings Charm – however, adding your settings pages can be a bit challenging because you’re supposed to transparently save the user’s preferences which can be tricky given the unload event won’t fire on the settings pages. So in this blog post I’ll cover the three main components of making a working settings page.

Registering the Settings

The first step is connecting your settings pages to the Settings charm in the first place. So in your default.js (presuming you’re using the grid app as your starting point) paste the following code immediately under the variable declarations (so it happens first):

// Register Settings Values

app.onsettings = function (e) {

e.detail.applicationcommands = {

“about”: {

href: “/pages/about/about.html”,

title: “About”

},

“settings”: {

href: “/pages/Settings/Settings.html”,

title: “Settings”

}

}

WinJS.UI.SettingsFlyout.populateSettings(e);

};

This will register two pages on the settings menu – one for About and one for Settings. (Which I should probably call something different.)

Settings Page HTML

The next step is to convert the HTML in the Page Control .HTML file so that it can be used by settings. That should look something like this:

<div id=”settingsContainer” data-win-control=”WinJS.UI.SettingsFlyout” aria-label=”About the application” data-win-options=”{settingsCommandId:’settings’,width:’narrow’}”>

<div class=”win-ui-dark win-header” >

<button type=”button” onclick=”WinJS.UI.SettingsFlyout.show()” class=”win-backbutton”></button>

<div class=”win-label”>Server Settings</div>

</div>

<div class=”win-content”>

<div class=”win-settings-section”>

<form>

<!– Insert settings UI here –>

</form>

</div>

</div>

</div>

The keys here are:

  • Provide a DIV attached to the WinJS.UI.SettingsFlyout class including options for the command id and the preferred width (narrow or wide.)
  • Provide a unique ID for the DIV so you can fetch it in code.
  • Inside an inner set of DIVs (classed with win-content and win-settings-section) include the controls and labels to capture your configuration.

Settings Page JavaScript

The Page control javascript that was generated has a nice structure, but it also has some problems. Left as is, the unload event will never be called. That’s a problem since the Windows 8 UI guidelines call for no save button. When the user clicks outside the settings page their settings are supposed to be saved automatically. We can make this happen automatically by registering the afterhide event on the WinJS.UI.SettingsFlyout container. However, this will provide a relatively odd context for the item when it comes back in, so we need a way to work around that. Here’s a sample of some of the code we need to make this all work:

var self = null;

WinJS.UI.Pages.define(“/pages/Settings/Settings.html”, {

ready: function (element, options) {

getSettings();

document.getElementById(“settingsContainer”).winControl.addEventListener(“afterhide”, this.unload);

self = this;

},

unload: function () { // Doesn’t appear to be called

self.updateSettings();

},

updateSettings: function () {

updateSettings(settings);

storeSettings(settings);

},

});

I’ve omitted some of the lines for brevity. In this case we’re creating a ‘self’ variable that we’ll assign to this so we can use it later – that’s going to help fix our event handling concerns in a moment.

Inside the ready method/event we get our settings and apply them to the HTML – That’s being done in getSettings(). Then we register our afterhide event and finally we set our ‘self’ variable to ‘this’ so we’ll have it later.

When the settings page is hidden it calls the unload function which uses the ‘self’ variable we created earlier to call updateSettings. Again the self variable is necessary because this within the context of an event handler is the DOM item that triggered the event – which isn’t what we want. The updateSettings uses helper functions to update the computer settings from the DOM and then store them.

As said earlier, unload doesn’t get called automatically and you’re supposed to be making your updates when the user makes them. That’s fine for toggle buttons but for text boxes there aren’t good ways to capture the end of the textbox entry. I know you would normally expect to be able to use onblur but this doesn’t work if the user clicks off the settings page fragment, so we need something that will get the form after it’s been pulled from the screen, thus the afterhide event.

It’s convention to save variables without a save button so you’ll want to save all the variables from the screen to application settings as soon as the user exits. That is the job of the storeSettings() method:

function storeComputerSettings(computerSettings) {

var roaming = Windows.Storage.ApplicationData.current.roamingSettings;

for (var prop in computerSettings) {

roaming[prop] = computerSettings[prop];

}

}

In my case I pass in an object with the appropriate properties defined. I just take those and stuff them into the roaming settings for the application. Once they’re there I can come back and access them again – even on different devices. You’ll note that the approach here will simply push anything in the object passed in, into roamingSettings.

So with these pieces you’ve got a settings page that can store values when the user exits the settings page; something that should be simple that was far more complicated than necessary.