You’ve been seeing it for a while now with Google’s Reader, Gmail, and most recently, on Facebook. Probably, you, too, would like to write RESTful evented JavaScript applications. Well, fellow developers, meet Sammy.js, a tiny JavaScript framework built on top of jQuery. Sammy utilizes the URL hash (#) to allow you to create single page AJAX applications that respond to your browser’s back button. Interested?
In this article, I’ll be providing a short overview of the framework, and then a brief demonstration of what it’s like working with Sammy.js, with the hope of enticing you enough to consider it for your projects.
Setting the Stage
“Sammy.js is light both in size (<20kb) and footprint. Pull it into your already started applications.”
Sammy.js is being put together by Aaron Quint, a web developer out of Brooklyn, NY. Its API is modeled on the popular ruby framework, Sinatra, and is great for both simple and complex applications. It’s easy to get into, and can be pulled into your existing projects. It’s not an all or nothing proposition; so let’s take a look.
Sammy.js allows you to write single page apps, much like Gmail. You can maintain the state of your app with the url, without having to refresh or change the page. There are other MVC JavaScript frameworks, like SproutCore, which tend to be all encompassing. But with Sammy, you have a light (~20kb) framework, capable of invoking several instances simultaneously (ie. running multiple apps in the same document).
Opening Act
Installing Sammy.js is pretty straightforward. Head on over to the download page, grab a copy and move, sammy-0.5.4.min.js
to where you store your project’s libraries (typically /js for me). For the purpose of this article, I will be using version 0.5.4, but you may be inclined to try sammy-latest.min.js
. You’ll also need a copy of jQuery, at least v. 1.4.1. As with most jQuery plugins, order is important: jQuery, before Sammy.js, before your JavaScript. I tend to put my JavaScript at the bottom of the page, because it blocks other items from loading in parallel, giving the impression of a slower loading page. So far we have:
<!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Sammy.js Example</title> </head> <body> <div id="content"></div> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script type="text/javascript" src="js/sammy-0.5.4.min.js"></script> <script type="text/javascript"> // your script goes here </script> </body> </html>
Now to start coding our app. To keep things simple, I’m working inline, which isn’t the best practice. Adding a Sammy.js application is as simple as assigning it to a variable, which I’m calling ratPack. On our page we’ve defined a div with the id “content” upon which our application will be acting. We indicate this as follows:
var ratPack = $.sammy(function() { this.element_selector = '#content'; // routes will go here });
The importance of the element selector is that we can have multiple instances of Sammy.js running in our document, affecting different elements.
Main Attraction
Sammy.js uses the path, as defined in the URL hash, and the common HTTP methods (get, post, put, delete) to determine a callback function to invoke. These are typically known as “routes”. Some examples from around the web would be:
As an example, we’ll sketch up a mailbox application. Let’s first setup the default route of our app, which will land on #/inbox.
this.get('#/inbox', function(context) { context.app.swap(''); context.$element().append('<h1>inbox</h1>'); });
Here, you can make the callback function do whatever you’d like. Since I’m displaying an inbox, I’d probably want to make an ajax call and retrieve a list of messages. However, for the sake of simplicity, I’m just going to return a h1
tag. The context.app.swap('')
tells Sammy to replace what’s in my content div, rather than just appending to it.
In order to get this working in the browser, we’ll want to run the app using jQuery’s document ready function and pass it to our starting URL, as defined in the above route.
$(function() { ratPack.run('#/inbox'); });
And that’s it. We should now be able to load our document in a browser, the app should launch and navigate us to our inbox.
Next, we can create another route to handle labeled messages:
this.get('#/label/:name', function(context) { context.app.swap(''); context.$element().append('<h1>' + this.params['name'] + '</h1>'); });
Sammy uses the colon var syntax (:var) to return parameters for us to filter our messages. Again, I’m just displaying the name of the label.
To this point, we’ve only been using the “get” HTTP method. Say we were to create a form and route it to #/compose:
this.get('#/compose', function(context) { context.app.swap(''); context.$element().append('<h1>say hello to?</h1>' + '<form action="#/compose" method="post">' + '<input type="text" name="to" />' + '<input type="submit" name="submit" />' + '</form>'); });
Now we can setup a route to accept the posted data and have Sammy parse it for us.
this.post('#/compose', function(context) { context.app.swap(''); var to = this.params['to']; context.$element().append('<h1>hi ' + to + '</h1>'); });
That’s the basics. A simple API, powerful enough for projects both big and small. If you are following along with the code, we can add some navigation for ease of clicking.
<div id="nav"> <ul> <li><a href="#/inbox">inbox</a></li> <li><a href="#/compose">compose</a></li> <li><a href="#/label/drafts">drafts</a></li> </ul> </div>
Encore
Of course, Sammy.js has a lot more to offer than simply defining routes in the app. More advanced users can explore custom events and namespaces, for event-driven applications. Aaron is trying to keep the core of Sammy.js as tight as possible, but it also comes with a lot of plugins. There’s a title plugin, that allows you to easily set the document’s title for different routes. There are several templating systems, including haml and mustache. There’s a nice-looking form builder and Sammy.Store, “an abstract adapter class that wraps the multitude of in browser data storage into a single common set of methods for storing and retreiving data.”
I hope you’ve enjoyed this quick look at Sammy.js and are ready to consider using it in your applications. Let’s hear your thoughts on Sammy.js in the comments!