Backbone.Model Gotcha With options.url
There is a (maybe) peculiar gotcha to be aware of with Backbone.Model and certain attributes passed in as options vs attributes.
tl;dr Passing a url parameter to a collection.fetch()
call will set that url on the Backbone.Model directly
UPDATE: The particular "bug" described in this post has been removed in the current master branch of the project, but is not part of the official release as of the time of this writing.
Here is an example that has bitten me twice now. After that, we'll finish with a better solution.
In a Marionette.CollectionView
I was trying to do a paginated load of the view's Backbone.Collection
instance. The following code has been modified for the sake of example:
if @gallery.get('page') < @gallery.get("total_pages")
nextPageUrl = "#{@gallery.url()}?page=#{@gallery.get("next_page")&per=#{@gallery.get("per_page")}"
@collection.fetch(url: nextPageUrl,remove: false).done( => ...)
Options passed in to most Backbone methods will get passed all the way through to any subsequent xhr and callback methods intact (usually via a _.clone
). If options.url
is provided, that same url
will be in the options
hash that is passed to the instantiation of the new Backbone.Model call as part of the reset
or set
command in the fetch()
success callback.
Normally this doesn't cause any unintended side effects as it's the first attrs
hash parameter that gets set on the model, and not the options
hash. However, Backbone.Model has three very special modelOptions
that will be attached directly to the model if provided:
var modelOptions = ['url', 'urlRoot', 'collection'];
And inside the Backbone.Model function declaration these modelOptions
are used via:
_.extend(this, _.pick(options, modelOptions));
So, using the example code, each model returned from the fetch with have its url
attribute set to whatever the calculated value of nextPageUrl
was in the fetch call. It doesn't matter what urlRoot
or url
functions/attributes you declared in those models, the url is now what was in options.url
.
Going back to my original bad implementation, the correct way to do this is to create a url
method in the collection itself that creates the dynamic url, and then you can just call @collection.fetch(remove: false)
without the need for a url parameter.
Written by Craig P Jolicoeur
Related protips
1 Response
For anyone interested, here is the commit where the modelOptions were removed from master: https://github.com/jashkenas/backbone/commit/3bfbcd4123a19f9
Currently, only the "options.collections" value is set directly, "url and urlRoot" have been removed.