Announcing Backbone.js: Models, Collections and Views in 2.4kb
documentcloud.github.com
documentcloud.github.com
I too am a jQuery developer, but not your typical one. I tend to avoid slapping plugins together and write most of my own things from scratch, in my own pythonic classical style. I also tend to use the little jQuery helper methods and CSS selector tools purely as an interface to the DOM. The hard work is all done via classes, which drastically reduces the code that I write. I see other not-so-skilled jQuery script kiddies out there piecing together documents full of $('#blah') this and $('#bloo') that with little regard for chaining or simplifying things. I digress, as that is not the demographic for this wonderful library of code.
Here is an example of what kind of code I have been writing as of late: http://dpaste.de/pKOi/ -- as you can see, there is a small bit if boilerplate required and a 'var self = this' inside of each class method that is required. That's more for my own personal style actually, to help with preventing loss of 'this' scope down the road. Anyway... over time this code just sort of piles up and it would be nicer to 1) have a better way to define and organize it all, and 2) all of the great model/collection/validation stuff looks excellent! Evented programming is brilliant to, and the fact that a thousand pieces of code can all stay in sync thru events is just fantastic.
I would advise the GP poster to pick up some class implementation (or roll his own), and use some bind function instead of all the `self`s (if only because other JavaScript programmers will recognize the style better). One that seems to work reasonably well for simple use cases is John Resig’s suggestion, http://ejohn.org/blog/simple-javascript-inheritance/ though one thing to keep in mind with that implementation (just as with the poster's) is that new instances must be created with `new`.
That one is supposedly inspired by base2: http://code.google.com/p/base2/source/browse/trunk/lib/src/b...
However you decide to do it, the prerelease versions of Resig’s upcoming book are quite helpful in understanding how these designs work and all the tricky corners of JavaScript closures and object inheritance.
We use Backbone.js at DocumentCloud for our document workspace. It took a few weeks to pull out all the pieces, but we rely on the JavaScript MVC that Backbone gives us for the entire workspace. (That too will go open-source, someday soon enough.)
I am personally planning on integrating Backbone into NewsBlur, an RSS feed reader, which currently has an ad-hoc model system. Backbone would give it the ability to update stories and feeds without having to remember where all of the stories and feeds are on the page.
Anyway, Backbone takes a bit of getting used to, but it is fairly easy to read the annotated source to see exactly what's happening. And once you do learn the Backbone.js conventions, hard problems become much easier on the front-end.
N+1 across the internet will suck.
I assume it's early days, but please consider this issue. It's killed a bunch of otherwise interesting libraries.
For saving, a single update often needs to be a single request, and the UI needs to know that the update has been applied successfully. If you need to do a bulk update, then use "set", not "save", and make a custom Ajax call for the bulk operation.
Finally, Backbone.sync is the lowest-common-denominator default REST request, which will work for many applications. You can and should override it if you have more specific needs -- using timeouts to aggregate many granular saves into a single HTTP request is a great idea for some applications...
As an example, I am currently working on a project that has a basic profile page. So on the server side, I have my nice OO representation of a Profile object, complete with properly defined public and private variables, a slew of functions, and a save() function that validates saves the data to the database.
When I display that page to the client, I have a PHP view which takes the data from the model and then renders it. In the view, I do currently use jQote2 to do some basic client-side templating where appropriate (for example, displaying all of the friends of the profile's user).
Now, the Profile page features the ability to edit profile fields. There is jQuery involved here. Currently, I just have a function that is called when the "Save" button is clicked that gathers up all the various data from my input fields and whatnot, and sends that off as JSON to be saved on the PHP side of things.
Is this someplace where Backbone.js would make sense? Would I then have to have a representation of my model both in PHP and in Javascript? And my PHP view would contain several Javascript sub-views? And when I do save the model on the Javascript side of things, am I then just executing database queries on the PHP side, or am I re-loading the model, changing the attributes, and then using the PHP model's save() function?
I guess I'm just confused as to where this fits into the grand scheme of things. There's a part of me that certainly likes the idea of data binding and having smart re-rendering of parts of my pages based on when models change, but I'm just unclear on how this fits into my existing PHP MVC stuff.
However, if you have an application with a lot of JavaScript interactivity, or a single-page application where the entire interface is driven from JavaScript (this is the case for us), then it helps to structure your client-side code with a little more oomph than just jQuery provides.
Taken to the extreme, in our case, the DocumentCloud workspace is effectively an empty body tag, and all of the HTML rendering and interesting logic happens in JavaScript models and views -- you never have to refresh the page. The server-side Rails code becomes smaller and less complicated, essentially delegated to performing validations and authentication and serving JSON to the client. Think GMail, or New Twitter, or 280 Slides...
So basically this is for those folks who are making real "web applications" -- meaning applications where a lot is happening on the client side, typically more of a "single URL/page", with dialog boxes and whatnot as opposed to a bunch of pages in the more traditional "web site" sense.
I have often considered trying out Cappuccino, but for some reason none of the websites I build end up being "web applications" in this sense. But I can't help but wonder if that's because they aren't, or if it's because I'm not thinking about them the right way.
It's outside the scope of this topic, but I can't help but ask: "How do you know when a website becomes a web application"? Is it the scope of the problem (trying to do "one thing", e.g. edit a photo, vs. presenting an entire web site full of information?) Or is it truly just a preference thing? I can only think that as projects like Node.js gain prominence, the lines will continue to be blurred...
Backbone supplies structure to JavaScript-heavy applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing application over a RESTful JSON interface.
"key-value binding and custom events": When a model changes its state, other JavaScript objects can listen for that change and be notified. It's the usual inversion-of-control pattern, but especially crucial for models and views. A model has no business knowing about what views may or may not currently be present in the UI. Instead, the views listen to changes in the model, and update themselves accordingly.
"rich API of enumerable functions": JavaScript arrays are pretty feature-poor, at least in terms of things that will work cross-browser. Backbone collections include all of these handy functions for working with your data:
http://documentcloud.github.com/backbone/#Collection-Undersc...
"views with declarative event handling": Instead of creating a mess of nested jQuery "bind" or "delegate" calls, it's nice to just declare what elements in a view should be hooked up to specific callbacks:
http://documentcloud.github.com/backbone/#View-handleEvents
"RESTful JSON interface": The persistence strategy for Backbone can be swapped out for something different (Websockets, Local Storage, CouchDB), but the default is to fire off a standard JSON Ajax call when you call "model.save()"...
Hope that helps a little.
For anyone unclear about REST, try this: http://tomayko.com/writings/rest-to-my-wife
Edit: It looks like it's taken straight from the source (http://github.com/documentcloud/backbone/blob/master/backbon...) using Docco: http://jashkenas.github.com/docco/
Is there an IDE for serious JavaScript development? Right now for JS work I use TextMate with a bunch of custom tag triggers.
IDE support is still kind of lightweight, but there are several options out there: http://haxe.org/com/ide
I use Geany, because I only really need context-sensitivity, highlighting, and search+replace.
* js-model is explicitly inspired by Rails' ActiveRecord models, and a lot of these points fall out from that fact...
* In js-model, a collection and a model class (constructor function) are the same object. This is a big problem in client-side code -- you don't always want to have just a single collection of say, notes. That makes sense in a one-database-per-app, one-table-per-model world, but not so much in JavaScript.
* Backbone sets up the prototype chain so that you can continue to extend (subclass) your Models, Collections, and Views.
* Backbone includes a richer set of enumerable functions, based on Underscore.js, so you get native performance in browsers that support them natively.
* js-model's validation and errors API mimics Rails' Errors object, which may or may not be what you want.
* Backbone includes Views, and js-model sticks to models.
That's just a list of things off the top of my head. It's an amazing example of convergent evolution in code -- and I think it's much more widespread than this. In my experience, many folks who work on big JavaScript projects end up with an internal framework that bears an uncanny resemblance to Backbone.
Backbone looks like it forms a much more cohesive package though, which is nice.
BackBone.js Models are also mutable. This is probably the only part of the design I would have handled differently at the cost of responsiveness in browsers with slower JS engines. In my experience it's too easy to accidentally corrupt the data which populates many UI components if you're passing mutable references around.
If we didn't have Backbone, we would probably call a main JSON sync function repeatedly, and iterate on this new data updating the different parts of the page "manually".
Is that it?
http://cl.ly/b043f31cd91dfdac8918
There, Recommendations, Friends, Followers, and Memberships are the models, and render off the contents of that JSON. Of course, Twitter should really be bootstrapping all of those bits of JSON into the initial page load, instead of firing off six requests immediately...
However (and this is another conversation altogether), I don't think that you really want to structure your client-side application around faux-routes. Maintaining browser history with "hashchange" is important, but hardly the central aspect of a JS app. Usually you want to reserve history changes for special states that deserve to be bookmarked, not for every single action performed.
For the record, this is the little module that we use to record and listen for "hashchange" events:
All I'm saying is that you don't need to ape the server-side paradigm (one URL, one page) quite so closely. Use a module that gives you URL setting and tracking with "onhashchange", by all means, but you don't have to shoehorn your application into it.
Todo = Backbone.Model.extend
done: ->
@get("status") is "done"
toggle: ->
@set status: if @done() then "active" else "done"
Doing a quick Backbone.coffee version would be fun though, hmm...Isn't this the kind of thing that coffee would be aimed at?
The first thing you would do is override Backbone.sync to save your models to Local Storage instead of the server:
But if you are doing something public facing, you can get it indexed by Google with a little elbow grease:
http://code.google.com/web/ajaxcrawling/docs/getting-started...
"New Twitter" takes this approach.