Wednesday, August 31, 2011

New guy in town: knockout.js

Today we're going to take client-side JavaScript to a whole new level with the MVVM pattern using knockout.js.

The "why"


Imagine you're writing an application using, let's say, WPF or Silverlight. What's nice is that you have a clean separation of concerns between what's being displayed in terms of the layout (which is in fact the first V in MVVM) and some object backing up that view (which is the VM in MVVM in this case). This allows the application to be extensible and well structured.
Granted you can make a mess everywhere and MVVM architecture is no exception. You still have to use your brain while coding :)
Up until recently there has been no framework giving you the opportunity to have that kind of clear separation in JavaScript. Granted there have been tools like ExtJS and jQuery to help you out with modern UI elements like calendars and grids as well as low-level operations on DOM and events but there has been nothing so far that'd help you out write in a clear MVVM declarative style. Now there is!

The "what"


That's quite simple: the mini framework is called knockout.js and implements the MVVM pattern in pure JavaScript and DOM (not necessarily HTML but that'll work for DOM creation as well).

The "how"


Well, here's the good part, which will be extremely easy:

<html>

<head>
<title>Example</title>
<script 
type="text/javascript" 
src="https://github.com/downloads/SteveSanderson/knockout/knockout-1.2.1.js">
</script>
<script 
type="text/javascript" 
src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js">
</script>
<script type="text/javascript">
$(document).ready(function() {
var viewModel = {
data: ko.observable("Hello, world!")
};

ko.applyBindings(viewModel);
});
</script>
</head>

<body>
<p>The current value of data is <span data-bind="text: data"></span></p>
<p><input type="text" data-bind="value: data"/></p>
</body>

</html>
See how there's no "Apply changes" button? This is because once you've entered the text into the input box it'll be automatically transferred to the viewModel object and since that's an observable it'll notify all subscribers about the fact that the value has changed and the text on the page gets updated automagically.

Going fancy


I'd like to see some fancy stuff in here like responding to button events and the like. Let's see how we can do that with KO:

<html>

<head>
<title>Example</title>
<script 
type="text/javascript" 
src="https://github.com/downloads/SteveSanderson/knockout/knockout-1.2.1.js">
</script>
<script 
type="text/javascript" 
src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js">
</script>
<script type="text/javascript">
$(document).ready(function() {
var viewModel = {
data: ko.observable("Hello, world!"),
show: function() {
alert("Current value is: " + viewModel.data());
}
};

ko.applyBindings(viewModel);
});
</script>
</head>

<body>
<p>The current value of data is <span data-bind="text: data"></span></p>
<p><input type="text" data-bind="value: data"/></p>
<p><button data-bind="click: show">Click me</button>
</body>

</html>
Again, the same page but with 2 additions:
1. A callback function called show as part of the viewModel
2. Declarative binding of the above function to a button using the last data-bind. Cute, isn't it?

I know that I'll put it to some good use in my next project. Just for the heck of it :) I like the idea that it is completely cross-platform and yet so incredibly easy to use!

No comments: