Reputation: 147
I'm trying to use Backbone with REST API:
Here the code
My model:
var PagesModel = Backbone.Model.extend({
idAttribute: 'Guid',
initialize: function () {
this.on('remove', this.destroy);
},
urlRoot: '/api/pages'
});
Collection:
var PagesCollection = Backbone.Collection.extend({
model: PagesModel,
url: '/api/pages'
});
View:
var PagesView = Backbone.View.extend({
el: '#pages',
events: {
'click .removePage': 'remove',
},
initialize: function (collection) {
this.collection = collection;
this.collection.fetch();
this.template = $('#pages-template').html();
this.collection.bind('change reset', this.render, this);
},
render: function () {
var template = _.template(this.template);
$(this.el).html(template({ pages: this.collection.toJSON() }));
return this;
},
remove: function (e) {
e.preventDefault();
var id = $(e.currentTarget).closest('ul').data("id");
var item = this.collection.get(id);
this.collection.remove(item);
$(e.currentTarget).closest('ul').fadeOut(300, function () {
$(this).remove();
});
}
});
And here I'm starting up application:
$(function () {
var pagesCollection = new PagesCollection();
var pagesView = new PagesView(pagesCollection);
});
I'm clicking or Remove and in Network inspector see this link
http://localhost:54286/backbone/function%20()%20%7B%20%20%20%20%20%20var%20base%20=%20getValue(this,%20'urlRoot')%20%7C%7C%20getValue(this.collection,%20'url')%20%7C%7C%20urlError();%20%20%20%20%20%20if%20(this.isNew())%20return%20base;%20%20%20%20%20%20return%20base%20+%20(base.charAt(base.length%20-%201)%20==%20'/'%20?%20''%20:%20'/')%20+%20encodeURIComponent(this.id);%20%20%20%20}
instead of /api/pages/{guid}.
What I'm doing wrong?
Upvotes: 1
Views: 84
Reputation: 8293
I still haven't figured fully why, but you can make it work by destroying your model after the end of its removal (Backbone does one last thing after triggering the remove
event: destroy the collection's reference in the model).
But what's even better, is using directly the destroy
function on the model, it will remove it from the collection automatically (use {wait: true}
if needed).
Edit:
Finally managed to locate the source of the problem. It's rather simple in fact. To override the model's url
(calculated with urlRoot
but that doesn't matter), you can pass Model#destroy
a url
option when calling Backbone.sync
(or something that'll call it).
Now you're thinking "but I don't!". But you do. The listener (Model#destroy
in your case) is given 3 arguments. Model#destroy
will take the first one (the model itself) as options
.
And here's the fail (I think Backbone needs a patch to this): giving an url
option to Backbone.sync
is the only time _.result
in not used to calculate the url. So you find yourself having as url the url property of your model, which is the function you see in your call.
Now, for a quickfix:
this.on('remove', this.destroy.bind(this, {}));
This will ensure the first argument of your Model#destroy
call is {}
(as well as binding the context).
Bear with me a little longer.
Now, if you're still willing to call Collection#remove
before destroying your model, here's a little hack: because (as I stated above) the remove
event is triggered before Backbone makes sure to remove the collection's reference in your model, you don't need the urlRoot
property in your model. Indeed, the model won't be in the collection anymore, but Backbone will still take the collection's url into account to get the model's url (as the reference is still there).
Upvotes: 1
Reputation: 4737
Not a definitive answer, but just going by the code in your question and the backbone.js documentation, the problem may be that you named your method remove
and this is getting in the way of the remove
method in Backbone.View
.
http://backbonejs.org/#View-remove
Update:
It also looks like the output you see in the network inspector is that the definition of the Backbone.Model.url
function is being appended. Meaning url
is not being properly called (Maybe the ()
is missing by the caller?). Are you overriding Backbone.sync
anywhere in your application?
Upvotes: 0