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:

modelBinder and the createBindings function, were created to take my bindings object and do all of the data-* goodness for me. It looks like this:

For my inputs and options sub-collections, I’m using some additional conventions I defined, mainly that the bind string is “value: “ + name for inputs and “options: “ + name for my array items. I could have achieved the same result with just a big list of custom bindings and a shorter createBindings() method, but doing this make the binding object cleaner and more maintainable, which I felt was worth the tradeoff.

After those additions, I swept back through my markup and replaced the data-bind attributes with Id’s.

Of course, this works exactly the same as before. The markup is certainly cleaner, and I feel like my JavaScript now owns more of defining ALL of the behavior of the page, but I’m not sure I’m 100% sold on this method yet. I like it in some ways, but I also wonder if I didn’t just dial up the complexity for the sake of getting behavioral data-* metadata out of my markup.

So what do you think? Is this cleaner, or do I need to have a stiff drink and accept data-* and Knockout for what it is? If you think the spirit is right, but the execution is wrong, I’d love to hear that too.

Here’s the gist for my initial code and markup, and the end-result, after my tomfoolery. If you want to play with this example yourself, I’ve created a Fiddle with a working sample that you can check out here.

Tagged with:
 
  • http://profiles.google.com/rniemeyer Ryan Niemeyer

    Hi Brandon-
    I have been thinking about this topic a bit lately.  There have been a couple of attempts recently to do this type of thing through a jQuery plugin (http://joel.net/wordpress/index.php/2011/06/unobtrusive-data-binding-for-knockout-js/ and also http://plugins.jquery.com/project/ko_bind).  

    I definitely get the unobstrusive movement, but have mixed feelings when it comes to using it with Knockout.  Two of my favorite things about Knockout are that you don’t have to write all that code to “wire-up” your app and that you really don’t need to know the IDs of your elements or add classes on elements just to identify them.   The declarative bindings handle all of this for you.

    I also think that the unobtrusive method starts to break down when you get into using templates, which is a usually necessary when dealing with collections of objects.  You would have to get creative, as you can’t select elements that are inside the script block that contains a template (at least a jQuery template).

    There are also alternatives that can be used if the logic gets too complex in the binding.  For your “enable: languagesToAdd().length > 0″, you could just write it as “enable: languagesToAdd” and it would evaluate properly.  DependentObservables can be used to encapsulate other complex logic down to a single field.  This has the added advantage of pushing the concept into the view model where it can be re-used.  Custom bindings are another option.  For example, if someone doesn’t like doing a data-bind=”enable: !someFlag()”, then they can either use a dependentObservable to represent the opposite or easily write a custom “disable” binding.  It can even just be a wrapper to the “enable” binding that passes the opposite of the value.  Anonymous functions in a binding are another troubling spot, but they can also be avoided with some extra work.  

    So, I can see why some would want to add the bindings unobtusively, but I feel like you partially miss out on the beauty of declarative bindings.  I do like the way that you did it though with a single object holding the binding information.

    If someone does use the unobstrusive method, then I would suggest keeping the  “wire-up” code cleanly separated from the view model.  I still think it is preferable for the view model to not need any direct knowledge of the view that is rendering it (the view depends on the view model, but not the other way around).

    Nice work on the screencast too!  I did notice a subtle bug in your dependentObservable though (sorry, I am a software tester, it is in my nature!).

  • http://www.userinexperience.com Brandon Satrom

    Ryan,

    Thanks for the comment!

    As for the bug, good catch! Since twitterHandle is an observable property, it’s viewModel.twitterHandle() instead of viewModel.twitterHandle. :) Thanks for the great reminder via your “10 things to know about KnockoutJS on day one” post (http://www.knockmeout.net/2011/06/10-things-to-know-about-knockoutjs-on.html). I’ve updated the gists.

    The “beauty of declarative bindings,” as you put it, is my biggest hesitation with this method, so I agree. I really like the declarative nature of Knockout, and the use of data-bind is quite elegant. So the suggestions of using dependent observables and custom bindings to move those concerns more solidly into the viewModel are appealing. Once you’ve done that, the concept count on the view itself drops close to par with using id’s to match properties on a binding object. I’ll have to give that a try and see how it feels in action.

    I’ll take a look at the plugins too. I avoided looking around for any other solutions at the start because I wanted to see how close I could come to something reasonable on my own. I second your conclusion: the binding object is nice, provided the wire-up is seperated from the viewModel itself (and likely would be in a seperate file), but you do lose out on some of the declarative goodness of Knockout.

    I still haven’t decided if I’m okay with that or not. :)

  • http://mutedsolutions.com Derick Bailey

    if i had 4 thumbs, this would be a 4-thumbs up post, brandon. seriously good stuff. i felt the same way about the data-bind attributes (especially the reference to the onclick=”" bit) but had not thought of a good way around this. I like your solution. it’s clean, simple, and would likely turn into a nice plugin if not a direct addition to the knockout-js core :)

  • http://www.userinexperience.com Brandon Satrom

    Thanks Derick! I appreciate the four thumbs up. :) I’ll have to think about the plugin or addition to core, perhaps I’ll send in a pull request when it’s more baked. :) Who knows, it might be accepted. Would at least make a decent option for folks wanting to eschew the data-bind syntax

  • http://www.biztalkguy.net/post/2011/07/21/knockoutJS-and-unobstrusive.aspx Biztalk Musings | knockoutJS and unobstrusive

    [...] and unobstrusive July 21, 2011 21:09 by btsguy http://userinexperience.com/?p=633 b2b56760-5970-4abf-b15b-1c34c8eab45e|0|.0 Tags: knockoutjs, unobstrusive Categories: knockout [...]

  • http://lostechies.com/derickbailey/2011/07/24/awesome-model-binding-for-backbone-js/ Awesome Model Binding For Backbone.js | ThoughtStream.new :derick_bailey

    [...] KO, yet, but I have to say I was blown away by the data-binding capabilties. Then, Brandon puts up this blog post and talks about how he made KO even more awesome by eliminating the data-* attributes that KO needs, from his HTML [...]

  • John Teague

    Very cool.  This is the reason I’ve been hesitant to use knockout too.  I would choose unobtrusive / clean separation over the declarative bindings.

  • Bot2099

    I think you are on the right track.  I agree with separating out the behavioral data from the markup.

  • http://www.userinexperience.com Brandon Satrom

    Thanks John! I would too, even when those bindings are simple. I just don’t think they tend to stay that way.

  • dotnetcoder

    Can we download the demo app?

  • http://www.userinexperience.com Brandon Satrom

    Sure, but let me clean it up a little bit, and illustrate the two options in parallel. I’ll let you know when I have it available.

  • http://sckrk.com Adam Pohorecki

    Interesting. Have you seen AngularJS? http://angularjs.org/

  • http://www.userinexperience.com Brandon Satrom

    I haven’t, but thanks for mentioning it. At first glance, I’m not to jazzed about the use of xml namespaces, but I’ll take a deeper look and reserve my opinion.

  • http://userinexperience.com/?p=656 KnockoutJS and Strongly-Typed Helpers in ASP.NET MVC | User InExperience

    [...] a screencast overview of KnockoutJS, a JavaScript MVVM framework. Shortly after that, I published this post, where I share my take on using Knockout in a more unobtrusive style, eschewing the standard [...]

  • Ralph Flora

    Coming from a Silverilght background…waiting for the jeers to die down…I can appreciate why Knockout works the way it does.  For example, the line “enable: languageToAdd().length > 0″ would actually just be a reference to a function on the viewmodel that performs the evaluation in the viewmodel, so you don’t have logic floating out in the view (the same way click is bound to addLanguage).  As for the declarative approach in the markup, it is because the view can know about the viewmodel, but the viewmodel should not know about the view.  That statement can be inflammatory based on which faction of MVVM zealot you’re speaking with, but that is a common, layered approach to the MVVM pattern.  So your bindings should always be in the view, but they should always be declarative (i.e. give a name to reference, but no functional code beyond that).  Unfortunately, KO doesn’t handle commands as full on objects but rather functions.  If they were full on objects (referencing back to that Silverlight thing…), you wouldn’t define the options for it declaratively, you would just reference the command object on the viewmodel, and the options would be on the command itself.

  • http://lostechies.com/derickbailey/2011/07/29/knockout-style-data-bind-attributes-for-backbone/ Knockout Style Data-Bind Attributes For Backbone | ThoughtStream.new :derick_bailey

    [...] “value” of the seelction instead of the text of the selection. I also want to explore what Brandon Satrom is building for Knockout, to remove the use of the data-bind attributes. I may be able to leverage what he’s building [...]

  • http://www.userinexperience.com bsatrom

    Ralph,

    I certainly see the appeal of this model for someone with a Silverlight background. That said, I think it would serve the JavaScript/web community to have at least one alternative, unobtrusive binding method for Knockout. I’ve started work on a plugin along those lines, so we’ll see what I can come up with. :)

  • http://www.userinexperience.com Brandon Satrom

    Ralph,I certainly see the appeal of this model for someone with a Silverlight background. That said, I think it would serve the JavaScript/web community to have at least one alternative, unobtrusive binding method for Knockout. I’ve started work on a plugin along those lines, so we’ll see what I can come up with. 

  • Anonymous

    i’ve been learning knockout the last few days and initially i was of the same opinion. in my normal web dev, i strive for super cleanliness in the view/html ensuring no JS “leaks” into the pages. I had reservations about knockout for the exact reason that code was leaking into the view.

    However, two things have changed my mind on this. Firstly, any code can be shifted to a dependentObservable, as Ryan pointed out, so this mitigates some of this leakage. But also, with the kind of super dynamic UI that knockout provides, do we really need our JS to be completely unobtrusive? Consider our usual motivations for unobtrusive JS : to keep the html clean enough that a) we guarantee accessibility b) markup is purely semantic, usually for SEO benefit.

    Now if you consider the type of app you will be making with knockout, accessibility is pretty much out of the question regardless of a few data-bind attributes here and there – because the whole thing is so JS-centric. And semanticism isn’t going to help much, as no search bot is going to be able to make heads nor tails of your app!

    That is not to say that we should start proliferating business logic in our views and stick JS everywhere; nor is it to say that we shouldn’t care about clean/semantic HTML. But it is fine to have to presentation-based logic in our views for the simple reason these aren’t your typical web pages, so the typical standards/best practices might not map perfectly to this approach (imagine trying to adhere to graceful degradation in a knockout app!!)

    Good post nonetheless, it’s definitely an interesting thought, and would be nice if you could override knockout’s default binding mechanism, so you could replace it wholesale with your own implementation (some kind of provider pattern?).

  • http://userinexperience.com/?p=689 Introducing the Knockout.Unobtrusive Plugin | User InExperience

    [...] month, I blogged about how much I love KnockoutJS, a fantastic JavaScript MVVM framework for creating rich, dynamic UIs. In that post, I also shared [...]

  • http://www.userinexperience.com Brandon Satrom

    @MrNicksta:disqus Thanks for your comment. Keeping the html clean is just as much about maintainability and SOC as it is accessibility and SEO, and mainanability/SOC are especially important for the types of rich, interactive UIs that Knockout tends to be leveraged for. If I have to switch between my HTML view and my scripts to make full sense of the behavior of my app, that becomes a maintenance nightmare over time, which is why I think an unobtrusive binding option could potentially be useful.

    Love the idea of swapping in binding providers! That might be something cool to look into.

  • http://technobuzz.wordpress.com/2012/08/04/knockout-webosphere/ Knockout webosphere « TechnoBuzz

    [...] 3) data-* [...]

Switch to our mobile site