问题
I have a Conversation model and a view that displays this model. This model is fetched from the server without any problem (the url property works fine then), and the view is rendered. However, when I attempt to destroy the model in a function of the view, I get the error 'A "url" property or function must be specified', even though when I display said url right before the destroy call, it is exactly the url it should be.
Here is the code for the model:
MessageManager.models.Conversation = Backbone.Model.extend({
defaults: {
uid: '',
title: '',
messages: [],
users: [],
dateUpdated: null,
isNew: true,
message: ''
},
url: function(){
var url = '/api/conversations';
if(this.get('uid').length > 0) url += '/'+this.get('uid');
return url;
}
});
And the view:
MessageManager.views.ConversationFull = Marionette.CompositeView.extend({
template: this.template(MessageManager.templates.ConversationFull),
childView: MessageManager.views.MessageListItem,
childViewContainer: '#message-container',
events: {
'click a#btn-delete-conversation': 'deleteConversation'
},
deleteConversation: function(e){
e.preventDefault();
var self = this;
console.log(self.model.url()); //This returns a correct url
self.model.destroy({//This fires the error
error: function(model, result, xhr){
console.log(result.responseText);
},
success: function(model, response, options){
MessageManager.conversations.sync();
AMMain.router.pNavigate('welcome/');
}
});
}
});
Can anyone give some insight on how to resolve this problem? Is there something wrong in the way I declare the model?
EDIT: It should be noted that other calls (like fetch or sync) on this model fire the same error, even though the original fetch works without a problem.
EDIT2: Well, not completely out of the frying pan yet, but I changed the way I defined the model's url, using urlRoot and the "id" attribute, and now the DELETE request is sent to the server without error.
回答1:
defsq answer is good. The only thing missing is to define the idAttribute
on your model, since it's not the convention-based id
field, but uid
.
MessageManager.models.Conversation = Backbone.Model.extend({
idAttribute: 'uid',
defaults: {
uid: '',
title: '',
messages: [],
users: [],
dateUpdated: null,
isNew: true,
message: ''
},
urlRoot: "/api/conversations"
});
You don't need to append the "id" manually. Just tell Backbone that your id attribute is uid
and everything else will work. In fact, you can event call mymodel.id
to get the id of the model -event if it's stored internally as uid
. :)
http://backbonejs.org/#Model-idAttribute
Personally I don't like all that default values. Everything will be undefined
if you don't set default values, which you can simply guard against with an if (undefined is a falsey
value).
if(!model.get("messages")){
//no messages
}
回答2:
It happens because you have to specify urlRoot
property of the model. Without it url
is not considered. So try this maybe:
MessageManager.models.Conversation = Backbone.Model.extend({
defaults: {
uid: '',
title: '',
messages: [],
users: [],
dateUpdated: null,
isNew: true,
message: ''
},
urlRoot: function() {
var url = '/api/conversations';
if (this.get('uid').length > 0) url += '/'+this.get('uid');
return url;
}
});
Documentation says:
urlRootmodel.urlRoot or model.urlRoot() Specify a urlRoot if you're using a model outside of a collection, to enable the default url function to generate URLs based on the model id. "[urlRoot]/id" Normally, you won't need to define this. Note that urlRoot may also be a function.
And source code for Backbone.Model
url method:
url: function() {
var base =
_.result(this, 'urlRoot') ||
_.result(this.collection, 'url') ||
urlError();
if (this.isNew()) return base;
return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id);
},
来源:https://stackoverflow.com/questions/26400601/error-a-url-property-or-function-must-be-specified-except-url-is-specified