Saving data is simple, right? What app isn’t complete without some sort of saving mechanism? And while I’m at it, it’s nice to be able to track when changes occur so I can tell if a user can press the save button or even leave the current screen. Which bring me to making my buttons smart enough to know that they are already involved in a asynchronous process, so commanding would be nice. Finally, if I want to save data, it might be a good idea to validate the input on the client (and the server).

There are a lot of moving parts involved with saving changes, and I cover these in my new Pluralsight course “Single Page Apps with HTML5, ASP.NET Web API, Knockout, and jQuery”.

image

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

Change Tracking

Change tracking can help make a user’s experience better and frankly, can make a developer’s life a little easier. For example, change tracking makes it easier to disable and enable buttons for saving/canceling changes. If no changes have been made, the buttons should be disabled.

image

If changes have been made, then these buttons would be enabled.

image

We can also prevent users from navigating off the page until they have either saved or canceled their changes.

image

So how do you wire up change tracking with a SPA? The Code Camper SPA uses a custom change tracking tool that ties into KnockoutJS. With some special tips from the KnockoutJS creators (Ryan Niemeyer and Steve Sanderson) Hans Fjällemark  and I wrote a component called the DirtyFlag. You can grab the DirtyFlag as part of the KoLite library on github or grab KoLite on NuGet.

image

How do we hook this up?

  1. Pull KoLite into your project.

  2. Wire up your model and tell it which properties you want to track changes on. (either pass an array of properties or the entire object)

Person = function () {
    var self = this;
    self.id = ko.observable();
    self.firstName = ko.observable();
    self.lastName = ko.observable();
    self.dirtyFlag = new ko.DirtyFlag([
    self.firstName,
    self.lastName);
    return self;
};
  1. Create a computed property on your viewmodel and check if the model is dirty or not
isDirty = ko.computed(function() {
    return myPerson().dirtyFlag().isDirty();
})

Now I can check the isDirty property on the ViewModel to see if changes were made or not. I can bind this property to bindings in the View, such as buttons, too.

Commanding

When I’m about to take an asynchronous action that saves data across the wire, I want the user to know the action is still pending (via a activity indicator) and I want to prevent the button from being clicked again. The commanding technique works great for this. Built into KoLite is another component called asyncCommand which handles these situations.

So when a user clicks this button …

image

It should be disabled and show an activity indicator like this …

image

So how do you do this? Pull KoLite into your project and instead of writing a method that saves the data, wrap that in an ko.asyncCommand. Just like the ICommand interface in XAML, asyncCommand has 2 methods you can define: execute and canExecute.

saveCmd = ko.asyncCommand({
    execute: function(complete) {
        $.when(datacontext.persons.updateData(speaker()))
            .always(complete);
    },
    canExecute: function(isExecuting) {
        return !isExecuting && isDirty() && isValid();
    }
})

Simply use the execute for the logic that will perform the save and define the conditions when it is appropriate for the user to be able to execute the command. Then in the HTML set the binding to use the command and optionally, the activity indicator.

Validation

Validation is a huge part of a good user experience. Users expect to be told how you want the data entered. Nobody wants to enter garbage and have to wait to find out that it’s wrong … or worse, not tell them why its wrong (or even what is wrong).

HTML5 has some great validation support built in, but not everyone can take advantage of HTML5 just yet. So what do we do? This is one reason I like the Knockout.Validation library: it works well without HTML5, but works better with it. This library is written by Eric Barnard and is also available on github and NuGet.

For example, I can make a property required by extending the observable.

self.firstName = ko.observable().extend({ required: true });

You can test this validation out in the live Code Camper demo here.

image

More?

10 posts is good, but there’s one more to go. In the next and final post I’ll cover mobility and responsive web design.