Hacker News new | comments | show | ask | jobs | submit login
Backbone 0.9.0 released (backbonejs.org)
216 points by singingwolfboy 1976 days ago | hide | past | web | 39 comments | favorite

Hey folks -- this should be considered a release candidate for a 1.0. We're currently running 0.9.0 on DocumentCloud.org; let me know if you have any trouble upgrading. There's a few things to watch out for, listed here:


Really, in the little over a year since the initial Backbone.js code drop, it's been incredible to see how many amazing apps have been built with it, a sentiment expressed concisely on Twitter this morning:



What a nice surprise! I started using Backbone this week, and this fixes six real issues I had with it:

- collection.fetch() now correctly calls model.parse() (I patched Backbone.Collection.prototype.parse(), but their fix is nicer)

- 'add' and 'remove' events now include the index (I had to work it out from scratch with sortedIndex())

- event 'bind' is now called 'on' (sensible as _.bind is already used for partial application)

- confusion over this.el and $()-wrapping is now cleared up

- events hash can now include functions (I like to avoid reflection where possible - even in JS)

- collection.create() now fires 'add' before the server replies (this makes writing a responsive UI much easier)

The last one is quite a significant change! Luckily my app is easy to fix, as I've only spent a few days on it.

Awesome that events hash now takes a function. I've needed that for a while, and should really get in the habit of submitting patches instead of waiting for others to do the work.

This is probably a little bit late for this release, but have you ever considered allowing arrays or strings with spaces on the value side of the events hash? This would allow you to define different functions to call in order when an event is fired, instead of just a single function that has to call them itself. I've run into a few situations where this would be useful, and seems like a very small change. Should I send a pull request?

Ha ha. That's actually already in 0.9.0, and I managed to miss it when reading through the commit list for the change log.

I've added the corresponding documentation, and added it to the change log for 0.9 as well.


I'm not familiar with the Backbone code or config. However, it sounds like you are setting an argument by specifying a function name in a string. If you want to specify multiple functions, then instead of specifying them in a string I'd say Backbone should accept either a string or a function as the argument value. That would let you define your event handler in-place, and you could define one that just calls a series of other functions.

No, that's not quite it. It's simply that you're now allowed to bind and trigger multiple event names in a single call, as in jQuery. For example:

    book.on("change:title change:author", function() {

Glad to see this milestone and some pretty helpful but not very breaky changes.

What is the recommended method for dealing with the optimistic model events? If my view gets the "destroy" event but the sync fails, do I have to parse the response on the "error" event to figure out that it corresponds to the destroy action?

It might be nice to have e.g. "destroy:failed" for the benefit of views that send off these requests and want to un-change the UI and show errors if they fail.

Views that are triggering optimistic destroys can listen for "error" on their model ... or (preferably) pass a direct error callback as an option, when sending the destroy. Remember that the return value of calling "model.destroy()" is a jQuery object that can be used to chain success and error callbacks...

Note that you'll also now get the new "sync" event, after the model has been successfully deleted on the server.

Great job. Congrats!

Few questions though,

1. Would you consider adding computed properties to models and collections?

2. I have a bindModel and close methods to all my views so that close() unbinds all the methods in the views that were bound to the models/collections and it also unbinds the view events. Any reason why such a mechanism is not embedded out of the box in backbone? Or am I missing something?

1. I'm not a huge fan of treating computed properties as real data values -- because fundamentally they're not. One is part of the model's representation as a resource, and can be modified and saved back to the server, and the other is simply a computation based on the model. As peregrine suggests, I think they're much nicer as simple methods. For example:

https://github.com/documentcloud/documentcloud/blob/master/p... ... and so on.

2. Not all views display a single model -- some views show data from several, some views display an entire collection, and some views don't have any models attached. Additionally, if you tend to throw away your views at the same time you throw away your models (we tend to do this), you'll never have to unbind anything, as both are GC'd together.

It's only the case that if you tend to remove views but leave their models around to be rendered by other views later, then you need this sort of thing. And if that's the case for your app, then by all means, adding a `close()` function or the equivalent is a great idea.

1. Agreed, it force you to do things cleaner I guess.

2. The way I get around the problem is that bindModel takes (model, eventName, func, context) so having a view that represent different models isn't an issue in this case because it ends up being passed to bindModel.


initialize: function () {

  this.bindModel(this.model.get('someCollection'), 'add', someFunc, this);

In the app I am working on, my models tend to live much longer than the views, and they usually get updates from the server.

Can you explain a bit more about #2? I'm not sure I understand fully what you mean.

1. Just add a method to a model or collection that does the computation. Javascript allows you to add methods to any object.

2. Good Question.

Right it does allow me to do that, but it doesn't get serialized and when a computed property depends on several attributes in the model, changing these attributes should also trigger the computed property change event.

The behaviour of clone has also change; instead of passing the whole instance to the constructor, it only passes the attributes. Could be worth noting for people who are upgrading (I hit an error because of that) :). Otherwise, great job!

Thanks for noticing -- I missed that in the commit logs. I've added a note about the change to the change log.

I'm trying to learn Backbone, I really am. But there's so many tutorials suggesting everything that I don't have a clue how I should structure a project and what to think about as a codebase grows.

Granted, I'm fairly new to Javascript, but - no offense meant - I can't get excited about node.js. Backbone is the first thing about Javascript that really makes me want to write it. And I know enough to know what I lack is primarily practical experience, but every step I take with Backbone feels like a misstep, because it seems like there's no one right answer by design, so I'm paralyzed.

What to do?

I was in a similar position to you a little while back. I found the annotated source of the TODO app on DocumentCloud a good start. I then found it was worth spending the money on Recipes with Backbone by Nick Gauthier & Chris Strom.

http://documentcloud.github.com/backbone/examples/todos/inde... http://documentcloud.github.com/backbone/docs/todos.html http://recipeswithbackbone.com/

That being said, I've always found the best way to learn, is to do. Come up with an idea for an app and build it using Backbone, with the help from the resources above. You'll learn a lot.

Thanks, I'll take a look at it. I'm always willing to invest cash in myself to buy good educational materials.

Rewrite one of your existing javascript-heavy apps in backbone. Having a clear goal will help.

Can't rewrite that which doesn't exist...yet :)

One of my friends recommends thoughtbot's "Backbone.js on Rails eBook": https://workshops.thoughtbot.com/backbone-js-on-rails

For someone who prefers to write Java on the backend (it can be made elegant and not enterprise-y, I promise), can its rubyisms (on rails) be mapped easily onto other web frameworks?


* Creating and destroying models with create and destroy are now optimistic by default. Pass {wait: true} as an option if you'd like them to wait for a successful server response to proceed.

* Two new properties on views: $el — a cached jQuery (or Zepto) reference to the view's element, and setElement, which should be used instead of manually setting a view's el. It will both set view.el and view.$el correctly, as well as re-delegating events on the new DOM element.

* When you don't know the key in advance, you may now call model.set(key, value) as well as save.

* Multiple models with the same id are no longer allowed in a single collection.

* Added a "sync" event, which triggers whenever a model's state has been successfully synced with the server (create, save, destroy).

* bind and unbind have been renamed to on and off for clarity, following jQuery's lead. The old names are also still supported.

* A Backbone collection's comparator function may now behave either like a sortBy (pass a function that takes a single argument), or like a sort (pass a comparator function that expects two arguments). The comparator function is also now bound by default to the collection — so you can refer to this within it.

* A view's events hash may now also contain direct function values as well as the string names of existing view methods.

* Added shuffle and initial to collections, proxied from Underscore.

* Model#urlRoot may now be defined as a function as well as a value.

* View#attributes may now be defined as a function as well as a value.

* Calling fetch on a collection will now cause all fetched JSON to be run through the collection's model's parse function, if one is defined.

* You may now tell a router to navigate(fragment, {replace: true}), which will either use history.replaceState or location.hash.replace, in order to change the URL without adding a history entry.

* Within a collection's add and remove events, the index of the model being added or removed is now available as options.index.

* Added an undelegateEvents to views, allowing you to manually remove all configured event delegations.

* Although you shouldn't be writing your routes with them in any case — leading slashes (/) are now stripped from routes.

Nodding my head the whole way through the changelog -- I just manually implemented undelegateEvents today. Looking forward to trying this out.

The sync addition is great, you can patch backbone to trigger a 'loading' event to accommodate it: https://gist.github.com/1500028

My biggest point of pain with backbone is the models, in one project I had to add lazy loading (pagination) and in another a sparse array implementation which was a lot of hassle.

The other point is boilerplate - there's a lot of it. projects like backbone-forms (https://github.com/powmedia/backbone-forms) try to fix it, but it's still a problem.

If you don't mind elaborating more, and/or opening tickets, I'm sure there are plenty of folks who'd be glad to help with the pain points.

Pagination shouldn't be too big of a deal -- that's precisely the sort of thing that Collections can make easy ... ditto for modeling a sparse array (although I'm fuzzy on why you'd need that -- if it's for performance only, you should be using something more low level)...

As for boilerplate, I'm not sure what Backbone-forms has to do with it -- if you're suggesting that Backbone should include UI widgets for auto-generating forms ... I think that's very far away from the role that Backbone is supposed to serve.

To clarify: backbone is so great and widely adopted because it is almost perfectly agnostic and easy to plug into other libraries. But, it feels like Connect, not Express. There's still boilerplate in my code to crush.

I don't like feature request issues, once we are done with the current project we'll send a couple of pull requests.

Looking forward to 'em.

The 'sync' addition is neat.

Is there any way in Backbone to get a list of all of a model's properties that have been changed since the last sync? model.changedAttributes() only works for the most recent change (and only inside of a 'change' event listener).

The reason I ask: I'm working on a system that only syncs model attributes that have changed - it doesn't send the entire JSON of every changed model. To do that it currently has to keep track of which attributes are 'dirty' or not for each model.

I'm having a hard time seeing how "changedAttributes" isn't exactly what you're describing -- the difference in attributes since the last time the model was changed/synced.

That said, if you need something fancier, and can't you simply listen on "change" events, and stash the last set of changed attributes where you can look them up later?

Yeah, that's what I'm doing now. Sorry, I realize I was being silly; the reason I needed this behavior is that I've overridden Backbone.sync to sync to the server in batches (every six seconds), rather than send off a new sync every time there's a change. I'd forgotten that I was doing something nonstandard there...

Man, I must have been doing something wrong with my models. I'm getting this error in my console when normally it triggers my validation errors:

"Uncaught Error: Can't create an invalid model"

Validation has gotten an overhaul -- I'm afraid it'll no longer allow you to create a model in an initially invalid state.

If you'd like to keep the same flow, first create an empty model, then `.set` the attributes on it.

I don't understand. If you create an empty model and you have a validate function, the validate function still runs and you aren't able to create the model.

Also, I don't fully understand the workflow for a "new" form. If the form needs to handle both a "new" model with no attributes (invalid state) and an existing model for update, how does one go about that? (I'm currently using a mock for the new state.)

I realize this are two different issues, but they are somewhat related to the problem of creating a model with no attributes, which is a model in an initially invalid state.

Looks like I managed to miss adding that bit to the changelog -- it's in there now.

Uh oh, and I thought it was clever to monkeypatch a function this.$el() into views that returns the cached jquery/zepto element and is mindful of changes to this.el ;)

"A view's events hash may now also contain direct function values as well as the string names of existing view methods."

Nice! I've always been wondering why I couldn't pass a function there.


Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact