I subscribe to the Morning Brew, and if you read this blog you probably should too.  It’s a great daily roundup of the latest news, mostly in the Microsoft development space.

Today there was a nice little post on how to simplify working with Knockout in ASP.NET MVC.

Loading KnockoutJS View Models from ASP.Net MVC, for faster page loads | Eric Hexter’s Blog.

I’ve been doing this for almost a year at my current client and it’s a great technique.  I just wanted to highlight some of the pitfalls you may run into that the post never discusses. The M in MVC stands for model of the current view, which sounds awfully similar to the view-model that Knockout uses.  In MVC this model is server side in your .NET language of choice, while most Knockout examples are working with view-models that are created on the client with javascript.

As the post notes, to most of us this immediately starts to smell of code duplication.  We can avoid this by sending our server-side model to the page via JSON, and then using the Knockout mapping plugin to automatically create an observable view-model.  Like most “automatic” paths this starts out just like the yellow brick road in the Wizard of Oz, until you end up in the Haunted Forest somehow.  To carry the simile further, it’s a powerful technique and you can still arrive at the Emerald City, just beware the flying monkeys.

Let’s look at a simple model and highlight some drawbacks you could run into using the mapping plugin.

public class PersonModel
{
    public string FirstName { get; set;}
    public string LastName { get; set;}
    public string FullName 
    {
       get { return FirstName + " " + LastName; }
    }
    public DateTime Birthdate { get; set; }
    public Address HomeAddress { get; set; }
    public Address WorkAddress { get; set; }
}

var p = new PersonModel 
{
    FirstName = "Nick",
    LastName = "Olson",
    Birthdate = DateTime.Parse("3/25/1984"),
    HomeAddress = new Address { /*address stuff */} 
};

No Computed Observables

If we seralized the object p to JSON and mapped it to a knockout ViewModel the first issue we’re going to run into is the FullName property.  When the magic happens Knockout only gets to see that the model has a property called FullName and it’s value is “Nick Olson”.  It doesn’t understand that is was a combination of two other properties.  Updating the first or last name propeties won’t update the full name on the client side.

Solution:  You can use the mappingOptions of the plugin to recreate the computed observables on the clientside.  It takes a while to understand exactly how the mapping options work but once you’ve done a few it starts to make some sense.  But this can be harder code to maintain just because of the nature of how it works and the time it takes to understand it.

DateTimes, JSON and Bears.  Oh my!

I have no idea where these Wizard of Oz references keep coming from but JSON and DateTime are not on friendly terms.  Depending on the serializer you are using to create the JSON, it could either come out as a string representation of the DateTime or Microsoft’s weird tick format that looks like this

"Birthdate" : "\/Date(1239018869048)\/"

Which is still a string, so you just have to explain to your users how to enter their dates into the textbox using the long count of ticks.

Solution: Add another property to your model that returns the DateTime as a string.  Use JSON.NET to serialize which gives a readable DateTime string format.  Or use the mapping options and actually create the property as a javascript date object.

Null Makes a Difference

In my initialize code up there I set a HomeAddress but not a WorkAddress.  When knockout maps this, all javascript knows is there’s two properties one returns something that has the properties of an address and the other is null.  This means that HomeAddress property will be an object as I would expect, but WorkAddress will be an observable function that returns null.  This means that depending on the data coming from the server your property could either be an object or function returning null.

That means that this statement will never be true.

vm.WorkAddress == null

Solution: Initialize carefully or use the unwrapObservable function to get the value before checking for things like null.

Performance

Mapping and change notification have a cost and depending on the complexity of your model, this can cause serious issues.  Knockout supports browsers all the way back to IE6 but try sometime comparing the javascript execution speed on IE6 vs. the latest version of Chrome.   Not only that, but the way IE calculates slow scripts can cause the mapping plugin to give you slow script warnings even on small to medium sized models.  Not only that but mapping makes EVERYTHING an observable.  Take a look at your model and see what things actually need to support change notification?  Probably a select subset.  Creating your own view models allows you to have a much finer grained control over that setup.

Solution: You have to understand the tools and when’s the appropriate time to step away from them.

Final Thoughts

Knockout is an awesome library and the mapping plugin can really speed up development and reduce duplication of code and effort.  But you have to treat all these tools like scaffolding.  Use it to get up and going but be prepared to rip out and replace once you start hitting the limits of where it can get you.