KnockoutJS and Unobtrusive JavaScript

I’ve been spending a lot of time with KnockoutJS lately, and I have to say that I really love it. MVVM & MVC frameworks (or MV* as some would say) in JavaScript seem to be maturing and evolving at a rapid pace, and I figured it was time to dig deeper into one of them. I chose Steve Sanderson’s Knockout, and even recorded a screencast about it last week.

Now I’m no MVVM zealot, and I don’t even classify myself an aficionado of the pattern, so I’m not going to dive much more into what MVVM is and why we’re seeing a proliferation of these types of libraries in JavaScript. Instead, I encourage you to read this post by Derick Bailey. It’s primarily about another MVVM framework (Backbone.js), but the beginning of the article has some very nice rationale around why frameworks like this are valuable. The biggest reason, I think, is that the nature of “MV-whatever” in JavaScript leads you down the path of cleaner, more organized and maintainable code. Using ViewModels in client code is a “pit of success” in my mind, as it gives us a single place to express the data and behavior for a given view (an hml page).

It’s with this in mind that I dug into Knockout. I started with an existing app, and added Knockout to a User Profile page that provides the user with a real-time view of what their public profile will look like on the site, as they make changes to the details of that profile.

Here’s a simplified version of my ViewModel, Knockout-style:

And a simplified version of my markup.

And that all works great. I have a nice separation, but I found myself wondering if the separation could be a bit cleaner. My primary concern was around Knockout’s method for binding, the data-bind attributes on each element.

Now I’m a big fan of the data-* portion of the HTML5 spec, for a number of reasons. Rather than using class or rel attributes to store arbitrary snippets of metadata to be used by JavaScript, we have an extensible—and HTML5-valid—alternative expressly created for the purpose. Data-* is great. The jQuery Validation Plugin (leveraged in MVC3’s unobtrusive client validation) uses it, as do countless others.

But I think there’s a difference between using data-* to store metadata for our scripts, and using it to embed JavaScript snippets in our markup.

Take this line from my addSpeaker page, for example:

I can’t help but feel that this line is expressing more than metadata. It’s expressing behavior. Two separate behaviors, in fact. First it provides a boolean expression that determines if the button should be enabled (“enable: languageToAdd().length > 0”). Then it specifies a click handler for that button (“click: addLanguage”).

I might be totally off base here, but the latter feels not that far removed from this:

The onclick attribute, and it’s siblings, has become something of a no-no with the “Unobtrusive JavaScript” movement of recent years, and for good reason. The same spirit of separating concerns that makes MV-whatever frameworks appealing is what drives us to find ways to keep markup, style and behavior in their proper places.

Now I’m not dismissing Knockout here, or any other MVVM framework, for that matter. These were all created by chaps far, far smarter than I am. For my use, though, I wanted to see if taking the data-* bindings out of my markup all together would result in a structure even cleaner and more maintainable. The rest of this post is the result of a couple hours of work in that direction.

I started by creating an object to hold all of my bindings for the page:

My bindings object allows me to specify the properties bound to text fields (of the same Id, by my convention), those bound to the options property of a <select>, and a set of custom bindings, where I can specify anything Knockout will support.

After I create this object, and just before I call ko.applyBindings(viewModel)—the line that tells Knockout to do it’s wondrous magic—I call this line:

Page 1 of 2 | Next page