Build Single Page Apps - Part 7 - MVVM and KnockoutJS

You knew it was coming, and you were right. MVVM and Knockout are 2 passions of mine and of course they are a big part of my upcoming Pluralsight course titled “Building Single Page Apps (SPA) with HTML5, ASP.NET Web API, Knockout and jQuery”. It’s less than 2 weeks to go before it’s due to go live!

You can catch up on the previous posts in this series here:

More on the Code Camper SPA

Part 1 - The Story Begins (What is the Code Camper SPA?)

Part 2 - Client Technologies

Part 3 - Server Technologies (the Data Layer)

Part 4 - Serving JSON with ASP.NET Web API

Part 5 - HTML 5 and ASP.NET Web Optimization

Part 6 - JavaScript Modules

Part 7 - MVVM and KnockoutJS

Part 8 - Data Services on the Client

Part 9 - Navigation, Transitions, Storage and Messaging

Part 10 - Saving, Change Tracking, and Commanding

Part 11 - Responsive Design and Mobility

 

MVVM

I’ve talked and written a lot about Model View ViewModel (MVVM) in the past, and if you aren’t familiar with MVVM you can catch up with a MVVM primer from this article. Are you back yet? Great. The good news for anyone who has done MVVM, MVP or MVC patterns (also known as the MV* patterns) is that you can follow this same pattern with JavaScript and SPA’s. In fact, its growing in popularity. KnockoutJS is a great library that handles data binding and integrates well with MVVM pattern. Together, they make a great pair. Let me explain a bit.

The HTML is our View and the data, which is very likely JSON, are our Model(s). So that covers the MV* part of MVVM. The way these fit together is important. We are apt to reuse Models in multiple Views, so it makes no sense to write redundant code with the copy/paste pattern when we need Person Model information in 4 or 5 Views. And how often is the data that comes from the web services and AJAX calls exactly what a View needs? Most of the time we need to tweak that data, adding new fields here, calculating other ones there, or cherry picking data form multiple Models for a View. This is where it is convenient to create an object that manages the View’s data … the View’s Models … the ViewModel.

The ViewModel can expose model data for the View to consume (via bindings and KnockoutJs). it’s not something that is specific for XAML … it works anywhere we have this separation of concerns.

The screenshot below shows the various types of data that the Code Camper SPA’s Favorites View needs. The data comes from various sources of models including Sessions (standard data), a list of dates of the events (lookup data), and filters. The first 2 come from web services while the latter (the filters) are completely driven by the View’s needs. All of these are aggregated together in a ViewModel.

KnockoutJS

We can certainly write jQuery to push the data into the HTML elements, and then pull them back out. That’s a lot of code that we don’t need to write though.  Knockout gives us data binding for that. KnockoutJS is a robust JavaScript data binding library that provides “observable” members which support two way bindings. I don’t cover Knockout in depth in the SPA course, but if you want in depth coverage of KnockoutJS you can catch my Pluralsight course on MVVM and Knockout here.

ViewModel Example

OK, I’ll give in … here is a quick example of a simple ViewModel. I shortened the contents of the functions because they are irrelevant really. The key here is that the list of publicly exposed members is at the bottom.

define('vm.speaker',
['ko', 'datacontext', 'config', 'router', 'messenger'],
function (ko, datacontext, config, router, messenger) {
var
// Properties
currentSpeakerId = ko.observable(),
logger = config.logger,
speaker = ko.observable(),
speakerSessions = ko.observableArray(),
validationErrors = ko.observableArray(),
// Knockout Computeds
canEdit = ko.computed(function () {   .......   }),
isDirty = ko.computed(function () {   .......  }),
isValid = ko.computed(function () {   .......  }),
// Methods
activate = function (routeData, callback) {   .......  },
cancelCmd = ko.asyncCommand({
execute: function(complete) {   .......  },
canExecute: function(isExecuting) {   .......  }
}),
canLeave = function () {   .......  },
getSpeaker = function (completeCallback, forceRefresh) {   .......  },
goBackCmd = ko.asyncCommand({
execute: function(complete) {   .......  },
canExecute: function(isExecuting) {   .......  }
}),
saveCmd = ko.asyncCommand({
execute: function(complete) {   .......  },
canExecute: function(isExecuting) {   .......  }
}),
tmplName = function () {   .......  };
return {
activate: activate,
cancelCmd: cancelCmd,
canEdit: canEdit,
canLeave: canLeave,
goBackCmd: goBackCmd,
isDirty: isDirty,
isValid: isValid,
saveCmd: saveCmd,
speaker: speaker,
speakerSessions: speakerSessions,
tmplName: tmplName
};
});

The ViewModel exposes the public members at the bottom, in the return object, and hides the rest. I’ll leave it here for now … there’s a lot of nice goodies in that code that may peak your interest. Next time, I’ll talk a bit more about how data flows throughout the client.