Background
In my previous posts on Binding in WinJS (see http://www.skimedic.com/blog/post/2012/11/27/MVVM-in-WinJS-Part-1-Observable-Models.aspx, http://www.skimedic.com/blog/post/2012/12/20/MVVM-in-WinJS-Part-2-e28093-Observable-Collections.aspx, and http://www.skimedic.com/blog/post/2013/02/22/MVVM-in-WinJS-Part-3-e28093-Binding-Initializers-and-Two-Way-Binding.aspx) we talked a lot about binding data for display in Windows 8 HTML apps.
Did you know that you can also bind to properties and attributes on markup, such as styles? Binding to styles can ensure that your application is consistent, and that your user can define aspects of you application according to their wishes. Of course, this doesn’t replace using CSS Style Sheets as the core for defining your application’s user interface, but does allow a series of customizations.
Related Posts:
This is part one of a series:
- Setting HTML Styles with Binding in Windows 8 WinJS Apps (this post)
- Creating Custom Application Events in WinJS
- Store and Share Settings in Windows 8 HTML/WinJS Apps
The Sample Application
To get started, let’s build a very simple app that will help to illustrate how the binding to styles works. The app is shown in Figure 1. By changing the toggle switches, the style for the fonts on the page will be updated to reflect the users wishes (as shown in Figure 2).
Figure 1 – The Sample App
Figure 2 – Sample app with styles updated
Creating the Core Application
Building the App
To get started, create a new WinJS Navigation project in Visual Studio 2013 (File->New Project…->Templates->Other Languages->JavaScript->Windows Store->Navigation App, shown in Figure 3). I named mine ApplicationSettings because this sample will also be used for working with Application Settings and the Settings Charm. Although we aren’t going to creating multiple pages, the Navigation app contains all of the layout to be consistent with the Layout Guidelines from Microsoft, and is my goto App Template.
NOTE: You can use Visual Studio 2012 for this sample, as we won’t be using anything that is only in Windows 8.1, but I do all of my work in VS 2013 for the Windows 8.1 support.
Figure 3 – Creating a new WinJS Navigation App
Finally, change the style to the light style by changing the ui-dark.css reference to ui-light.css in both the default.html and home.html pages.
Creating the Initial User Interface
Open home.html, and paste in the following markup:
<div id="contentContainer">
<div id="menuTarget" contenteditable="true">
This is some sample text to demonstrate the RadRadialMenu
</div>
<div>Another Test</div>
<textarea id="MyTextArea" rows="6" cols="100" width="600px"></textarea>
</div>
<div id="fontSettings" class="win-settings-section">
<div id="boldSwitch"
data-win-control="WinJS.UI.ToggleSwitch"
data-win-options="{title:'Bold'}"></div>
<div id="italicSwitch"
data-win-control="WinJS.UI.ToggleSwitch"
data-win-options="{title:'Italic'}"></div>
<div id="underlineSwitch"
data-win-control="WinJS.UI.ToggleSwitch"
data-win-options="{title:'Underline'}"></div>
</div>
Listing 1 – Markup for Sample App
The two divs and the TextArea are just sample content items that we will use databinding to update the style. The ToggleSwitch controls will be used to change the properties on the model so we can change the properties on the model and see the changes in real time.
To fill the TextArea with some sample text, open up home.js and add the following line to the pages ready event:
MyTextArea.value = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Pellentesque volutpat sodales rhoncus. In a rhoncus risus. Maecenas neque ante,
pharetra sollicitudin ante sit amet, venenatis consequat enim. Vivamus lacinia
hendrerit nibh, in consequat elit commodo vitae. Aliquam adipiscing rhoncus nisl,
non ultricies dolor lobortis eu. Nulla ac felis at mauris tristique tristique.
Etiam eget tincidunt velit. Cras vitae augue non purus ultricies facilisis et in nulla.
Mauris adipiscing dui quis felis lacinia ornare. Nulla vitae congue odio, sed
vestibulum nulla. Donec dignissim egestas metus, sit amet vestibulum nunc pretium
gravida. ";
Listing 2 – Adding Lorem ipsum to the TextArea HTML control
There isn’t a solid reason to move this to the JavaScript file through programmatic assignment, except that it makes it easier to format for this post.
Adding the Model
The model is very simple. Add a new file to the js directory and add a self executing function. In the function, set up some convenience variables to hold the style values (to help reduce the number of “magic strings” in our code). Add a NameSpace called Model, and use the WinJS.Binding.as() statement to hold the textSettings object. Remember that WinJS.Binding.as creates Observable models for us, so anytime the value changes, the UI will be notified and can act accordingly.
/// <reference path="//Microsoft.WinJS.1.0/js/ui.js" />
/// <reference path="//Microsoft.WinJS.1.0/js/base.js" />
(function () {
"use strict";
var normal = "normal";
var none = "none";
var bold = "bold";
var italic = "italic";
var underline = "underline";
WinJS.Namespace.define("UISettings", WinJS.Binding.as({
textSettings: {
textWeight: normal,
textFontStyle: normal,
textDecoration: none,
},
}));
})();
Listing 2 – Initial Model for Text Settings
Add the uiSettings file to the home.html as a script tag.
Adding the Binding Statements
Remember that the data-win-bind takes two arguments (three if using a binding initializer). The first is the property on the markup element or WinJS control, the second the property on the model that is to be used to set the value. For example, if we wanted to bind the textContent of a Span to the firstName property of the model, we would use the following code:
<span data-win-bind="textContent:firstName"></span>
Listing 3 – Sample binding statement
In the previous example, the binding statement bound to a single property on the root of the control and the model. If you need to bind deeper into the object (or element) graph, either side of the binding statement can be a path, or a “dotted” notation of the properties, starting at the root. For example, to change the color of the text, use the following code:
data-win-bind="style.color:textColor;">
Listing 4 – Binding the Style Color to the textColor property
If we apply this pattern to the font-weight property of the style, we will get an error through by WinJS – it doesn’t like special characters in the binding statements. Fortunately there is another syntax that we can use when the property names contain special characters to reserved words. Instead of prop1.prop2, we use prop1[‘prop2’]. To bind the Font Weight, Text Decoration, and Font Style properties, we use the following code in the Div named contentContainer:
data-win-bind="style['font-weight']:textWeight;style['text-decoration']:textDecoration;
style['font-style']:textFontStyle"
Listing 5 – Binding the model to an HTML control
We have to repeat this markup in the TextArea control due to the way the TextArea HTML control behaves (this is not a factor of WinJS or Windows 8, it’s an HTML thing).
The full markup for the contentContainer Div is as follows:
<div id="contentContainer"
data-win-bind="style.color:textColor;style['font-weight']:textWeight;
style['text-decoration']:textDecoration;style['font-style']:textFontStyle">
<div id="menuTarget" contenteditable="true">This is some sample text to demonstrate the RadRadialMenu</div>
<div>Another Test</div>
<textarea id="MyTextArea" rows="6" cols="100" width="600px"
data-win-bind="style.color:textColor;style['font-weight']:textWeight;
style['text-decoration']:textDecoration;style['font-style']:textFontStyle"></textarea>
</div>
Listing 6 – Full HTML Markup
Setting the DataContext for the Bindings
The final step that we need to do in this example is set the datacontext for the binding statements. Open up home.js and after the line setting the text for the TextArea, add the following line:
WinJS.Binding.processAll(element, Model.textSettings);
Listing 7 – Setting the DataContext for the DataBinding statements
And that’s it! Now you can change the properties in the model, run the app, and see the affects on the styles. For example, if you change the model to this:
textSettings: {
textWeight: bold,
textFontStyle: italic,
textDecoration: underline,
},
Listing 8 – Setting the bold/italic/underline styles in the model
Running the app presents the following UI:
Figure 4 – Updated styles using Data Binding
Modifying the Styles at Runtime
While this works nice, it isn’t very different from hard coding the styles into the page. To wire up the ToggleSwitch controls to the model takes just a few lines of JavaScript in a few convenience methods on the model, and setting the click event on the toggle controls.
Creating the Event Handlers
Start by opening uiSettings.js and adding a new NameSpace within the self executing function. We want the new NameSpace in the same function so we can take advantage of the variables we already defined.
WinJS.Namespace.define("UISettings", {
});
Listing 9 – Namespace for Toggle Functions
Create three functions, one for each style property, marking them as supported for processing. This allows them to be used in markup in the data-win-options attribute. Each event will get the checked value from the Toggle control and adjust the model accordingly.
setTextIsBold: WinJS.Utilities.markSupportedForProcessing(function (event) {
if (event.currentTarget.winControl.checked) {
Model.textSettings.textWeight = bold;
}
else {
Model.textSettings.textWeight = normal;
}
}),
setTextIsUnderlined: WinJS.Utilities.markSupportedForProcessing(function (event) {
if (event.currentTarget.winControl.checked) {
Model.textSettings.textDecoration = underline;
}
else {
Model.textSettings.textDecoration = normal;
}
}),
setTextIsItalic: WinJS.Utilities.markSupportedForProcessing(function (event) {
if (event.currentTarget.winControl.checked) {
Model.textSettings.textFontStyle = italic;
}
else {
Model.textSettings.textFontStyle = none;
}
}),
Listing 10 – Functions for changing the model
Finally, open hone.html and connect the onclick events for the WinJS controls to our new functions, as shown in Listing 11.
<div id="fontSettings" class="win-settings-section">
<div id="boldSwitch"
data-win-control="WinJS.UI.ToggleSwitch"
data-win-options="{onclick:UISettings.setTextIsBold,title:'Bold'}"></div>
<div id="italicSwitch"
data-win-control="WinJS.UI.ToggleSwitch"
data-win-options="{onclick:UISettings.setTextIsItalic,title:'Italic'}"></div>
<div id="underlineSwitch"
data-win-control="WinJS.UI.ToggleSwitch"
data-win-options="{onclick:UISettings.setTextIsUnderlined,title:'Underline'}"></div>
</div>
Listing 11 – Connecting the event handlers to the controls
See the Results
Run the app, and when you toggle the controls from off to on, the text on the page within the contentContainer div as well as the text in the TextArea are updated to Bold, Italic, and Underlined (as in Figure 2 above). There’s only one problem – when you toggle the Underline and Italic toggle switches, nothing changes. The Bold works, but the others remain the same. This is an issue with changing CSS through JavaScript. My next post will show how to handle the issue with Application level events.
Summary
Data binding works with not only traditional models and display elements, but also styles and any other property on HTML or WinJS controls.
About the author
Philip Japikse
|
Philip Japikse is an international speaker, a Microsoft MVP, INETA Community Champion, MCSD, CSM/ CSP, and a passionate member of the developer community, Phil has been working with .Net since the first betas, developing software for over 20 years, and heavily involved in the agile community since 2005. Phil works as a Principal Developer Advocate for Telerik, co-hosts the Hallway Conversations podcast (http://www.hallwayconversations.com), and is the Lead Director for the Cincinnati .Net User’s Group (http://www.cinnug.org). You can follow Phil on twitter via www.twitter.com/skimedic read his Telerik blog at http://blogs.telerik.com/skimedic and his personal blog at www.skimedic.com/blog. |