Backbone 0.9.0 released
backbonejs.org
backbonejs.org
http://backbonejs.org/#upgrading
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:
https://twitter.com/#!/donnierayjones/status/164012817584881...
Cheers!
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.
Note that you'll also now get the new "sync" event, after the model has been successfully deleted on the server.
- 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.
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?
2. Good Question.
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.
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.
example:
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.
book.on("change:title change:author", function() {
...
});I've added the corresponding documentation, and added it to the change log for 0.9 as well.
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?
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.
* 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.
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.
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.
I don't like feature request issues, once we are done with the current project we'll send a couple of pull requests.
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.
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?
Nice! I've always been wondering why I couldn't pass a function there.
Thanks
"Uncaught Error: Can't create an invalid model"
If you'd like to keep the same flow, first create an empty model, then `.set` the attributes on it.
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.