Client-side Sammy.js + Knockout.js in Coffeescript

I’ve been working on an HTML5 client application that leverages a bunch of cool Javascript libraries to implement a sophisticated data editing and visualization editor in the browser. In slightly more detail I’m using jQuery (of course), Sammy.js, Knockout.js, and D3js together to build this little monster. And I’m doing it all in Coffeescript.

More about that later however. Today we’re going to take a quick look at how to use Sammy.js (for client side routing) with Knockout.js for data binding and view rendering. There are actually great examples of how to do this already (see: http://learn.knockoutjs.com/#/?tutorial=webmail) but they’re written in native Javascript, not Coffescript.

Having already written two single-page applications (a basic Sammy.js page and a not so basic Knockout.js page) in Coffeescript and after a quick peek at the Javascript it looked easy to mash the Coffeescript from these two examples together and get it working. Ten minutes later it works 90% but the 10% that’s busted is completely fracked.

To digress for a moment and talk about Coffeescript I have to say that I hate it. Actually I don’t. I’m using it a lot and it saves me a ton of time. But as a C++ programmer the idea that I can write some code, compile it cleanly and then see such an enormous variety of spectacularly evil and unexpected runtime problems is disconcerting.

That said, pilot error is pilot error. It’s just that I prefer my foibles to remain a private affair between me and the compiler. But here’s the thing: Javascript generated by wrong Coffeescript misbehaves so spectacularly that it’s usually obvious that you botched the magic sequence of glyphs that is Coffescript. And the JS debugging tools are good (although what a mess the DOM is).

So anyway, I ran into one of these situations yesterday with my 90% working first attempt to get Sammy and Knockout talking. So I went looking for inspiration (i.e. code I could copy) but couldn’t find a good Coffeescript example so I wrote one.

Code for this example is available here: https://github.com/ChrisRus/minkosam

Also, here’s the example hosted on my server: http://chrisrussell.net/html5/minkosam/

Here’s the code:

 

HTML Page


<!DOCTYPE html>

<!–
MinKoSam.html
Minimal HTML5 application demonstrating the use of Sammy.js
with Knockout.js in Coffescript.

Copyright 2013 Chris Russell (chrisrus@encapsule.org)
Published under the Boost Software Licene v1.0
http://www.boost.org/LICENSE_1_0.txt

–>
<html>
<head>
<title>MinKoSam.html</title>
<meta charset=”UTF-8″>
<!– lib scripts –>
<script src=”./js/libs/jquery-1.8.3.js” type=”text/javascript”></script>
<script src=”./js/libs/sammy.js” type=”text/javascript”></script>
<script src=”./js/libs/knockout-2.2.1.debug.js” type=”text/javascript”></script>
<!– app scripts –>
<!– <script src=”./js/minkosam-handcrafted.js” type=”text/javascript”></script> –>
<script src=”./js/minkosam.js” type=”text/javascript”></script>
</head>
<body style=”background-color: white;”>
<h1>minKoSam.html</h1>

<p>
Minimal HTML5 application demonstrating the use of <a href=”http://coffeescript.org/”>Sammy.js</a&gt;
with <a href=”http://knockoutjs.com/index.html”>Knockout.js</a&gt; in <a href=”http://coffeescript.org/”>Coffescript</a&gt;.
</p>
<div style=”background-color: #F0F0F0; border: 1px solid #CCCCCC; padding: 10px;”>
This is a DIV that contains a DIV whose inner text is bound to the Knockout view model observable samPath.
<div id=”samPathDisplay” data-bind=”text: samPath” style=”background-color: #DDEEFF; border: 1px solid #CCCCCC;”>
STATE #1: initial value set statically in the HTML document source
</div>
</div>

<p>
[ <a href=”./minkosam.html”>./minkosam.html</a> ]
[ <a href=”#”>#</a> ]
[ <a href=”#/”>#/</a> ]
[ <a href=”#/hello”>#/hello</a> ]
</p>

<p style=”text-align: right”>Copyright 2013 <a href=”https://www.github.com/ChrisRus”>ChrisRus</a><br><a href=”http://www.boost.org/LICENSE_1_0.txt”>Boost Software License v1.0</a></p>

</body>
</html>

Hand-Crafted Javascript

Extracting the essence of the solution from the e-mail client example on the Knockout.js site, I authored the following JS by hand:
This works as expected in the minkosam.html page (uncomment out the include of minkosam-handcrafted.js).


function KoViewModel() {

var self = this;
self.samPath = ko.observable("STATE #2: initial value set during the initialization of ko.observable");

var sammyRouter = $.sammy(
function() {

this.get('',
function(context_) {
//alert(context_.path);
self.samPath(context_.path);
}
);
this.get('#',
function(context_) {
//alert(context_.path);
self.samPath(context_.path);
}
);

this.get('#/',
function(context_) {
//alert(context_.path);
self.samPath(context_.path);
}
);

this.get('#/hello',
function(context_) {
//alert("Hello!");
self.samPath(context_.path);
}
);

}
);

sammyRouter.run();

};

jQuery( function() {

var koViewModel = new KoViewModel();
ko.applyBindings(koViewModel);
//koViewModel.samPath("STATE #3: initial value set immediately following the binding of the view model");

} );

Coffeescript

Next I went over to the Coffeescript site and sat in their interactive compiler and hacked out the following Coffeescript that produces Javascript nearly identical to my handwritten code above:


## minkosam.coffee
#
# Take a look at ../minkosam.js which was hand authored and tested.
# I then sat in the Coffeescript editor and worked out the following
# which is transformed to approximately equivalent Javascript.

class ViewModel
constructor: ->
self = @
self.samPath = ko.observable "test"

sammyRouter = $.sammy( ->
@get '', (context_) ->
self.samPath(context_.path)
@
@get '#', (context_) ->
self.samPath(context_.path)
@
@get '#/', (context_) ->
self.samPath(context_.path)
@
@get '#/hell', (context_) ->
self.samPath(context_.path)
@
)
sammyRouter.run()
jQuery ->
koViewModel = new ViewModel();
ko.applyBindings(koViewModel)

@

So that’s it. The combination of these two libraries is very useful.

About Chris Russell

http://www.chrisrussell.net
This entry was posted in Internet, Software and tagged , , , . Bookmark the permalink.

2 Responses to Client-side Sammy.js + Knockout.js in Coffeescript

  1. il says:

    Thank you! this was helpful!

  2. This post has received quite a few hits. A quick update: Knockout.js is really cool and useful. Sammy.js is an interesting library but ultimately does more than what I want in ways that seem overly complicated to me. I’ve dropped the dependency on Sammy.js and moved on to use director.js. Director.js isn’t really exactly what I want either but it is comparably simple. See later posts on this blog if you’re interested in client side routing or Knockout.js.

Comment on this article