Reputation: 277
I've been playing around with Backbone.js and ran into something a bit unexpected. It seems that toJSON() (and as a result of attributes) will only return a JSON object if I explicitly set the attributes. Here's the issue:
toJSON()
functionI expected the call to return my object with all attributes (inherited and bound), but instead I got back an empty {}
object.
Here's the sample code:
var TestModelConstructor = Backbone.Model.extend({ name: "test", num: 483 });
var testinstance = new TestModelConstructor;
console.log(testinstance.name); //prints: test
console.log(testinstance.num); //prints: 483
console.log(JSON.stringify(testinstance.toJSON())); //prints: {}
console.log(testinstance.attributes); //again empty object
testinstance.newattr = "adding new attribute";
console.log(testinstance.attributes); //{} ????
//either set explicitly by calling "set" or via constructor/initialize
testinstance.set({ label: "i can setz attributez" });
console.log(JSON.stringify(testinstance.toJSON()));
//{"label":"i can setz attributez"}
console.log(testinstance.attributes); //{"label":"i can setz attributez"}
Either this behavior is strange or I missed something in the documentation.
Upvotes: 2
Views: 2170
Reputation: 13421
in fact you mixed it up
where you did:
var TestModelConstructor = Backbone.Model.extend({ name: "test", num: 483 });
you should have done:
var TestModelConstructor = Backbone.Model.extend({});
remark keep in mind the has does not need to be empty, but just for testing extending a new model without any custom methods is enough.
then, when you did:
var testinstance = new TestModelConstructor;
you should have done:
var testinstance = new TestModelConstructor({ name: "test", num: 483 });
remark here, you create a new object of that defined Model, and you give your modelObject some values, a name and a num.
these attributes are only available in the instance though, they are properties of the instance.
if you want those properties as defaults on every instance you should set them in the model definitions when you extend from Backbone.Model
. like this:
var TestModelConstructor = Backbone.Model.extend({
defaults: {
name: 'defaultname',
num: 0
}
});
remark every instance you now create will get 'defaultname'
as a name property (unless you create your instance with given values for the name property.
to sum it up:
var TestModelConstructor = Backbone.Model.extend({
defaults: {
name: 'defaultname',
num: 0
}
});
// create a test instance
var testinstance = new TestModelConstructor();
console.log(testinstance.get('name')); // output: defaultname
// create a testinstance and override the defaults (you can override them partially)
var testinstance2 = new TestModelConstructor({ name: "test", num: 483 });
console.log(testinstance.get('name')); // output: test
Upvotes: 1
Reputation: 9559
I think you should be using the defaults
parameter to the extend
function to set the defaults. Parameters passed to the extend function will be members on the class rather than attributes, which is what toJSON
uses.
var TestModelConstructor = Backbone.Model.extend({
defaults : { name: "test", num: 483 }
});
var testinstance = new TestModelConstructor;
....
See the defaults documentation for more details.
To be clear, the attributes Backbone.Model
uses are stored in the attributes
member of the class rather than on the actual class itself. This avoids confusing actual model data with functions that you call on the model and settings that you use to configure the model. It's these functions and settings that you're creating/setting when you pass arguments to the Model.extend
function.
So when you're trying to set testinstance.newattr
you should actually use testinstance.attributes.newattr
instead. This is what the .set
method is actually doing behind the scenes, so I'd recommend just using .set
.
Again, the attributes documentation has more details
Upvotes: 3