I'm working in Backbone.js
and I was wondering if you can set default values much the same way that you can set the default values of a model?
defaults() The Backbone. js defaults model is used to set a default value to a model. It ensures that if a user doesn't specify any data, the model would not fall with empty property.
The Backbone. js Views specify how your data looks like. They represent model's data to the users. They can be used with any JavaScript template library.
Anyways, the default value of a variable in JavaScript is null or undefined .
Backbone. js allows developers to develop one page applications and front-end much easier and better using JavaScript functions. Backbone provides different types of building blocks like models, views, events, routers and collections for assembling client side web applications.
What you can do is to set your defaults in the initialize
function.
defaults: {
display: 'list'
},
initialize: function() {
this.options = _.extend({}, this.defaults, this.options);
}
This will work for normal options, but would not override any special options (the ones that Backbone stores on the view object as well - ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName']
)
See a working demo: http://jsfiddle.net/dira/7MmQE/1/
var MyView = Backbone.View.extend({
options: {
enabled: true,
align: "left"
},
initialize: function (options) {
#be sure to do the '|| {}' here so 'new MyView()' works
this.options = _.defaults(options || {}, this.options);
}
});
https://github.com/rotundasoftware/backbone.viewOptions
Thanks to @BraveDave for pointing this out in a comment.
Here is the backbone issue where it seems like the core team is most likely to get rid of this.options
and the logic in _configure
altogether.
There is much confusion on this question and even a highly upvoted and accepted incorrect answer. Hopefully this answer demonstrates a truly correct solution as well as pointing out the bugs in all the other candidate answers.
To work in harmony with the Backbone.View
parent class, you are supposed to include an options
property of the object literal you pass to Backbone.View.extend
.
var OptionsInLiteral = Backbone.View.extend({
options: {flavor: "vanilla"},
initialize: function (options) {
console.log("OptionsInLiteral.initialize first argument", options);
console.log("OptionsInLiteral.initialize this.options", this.options);
}
});
Here are some examples and what they log to the console.
new OptionsInLiteral();
//OptionsInLiteral.initialize first argument undefined
//OptionsInLiteral.initialize this.options Object {flavor: "vanilla"}
new OptionsInLiteral({flavor: "chocolate"});
//OptionsInLiteral.initialize first argument Object {flavor: "chocolate"}
//OptionsInLiteral.initialize this.options Object {flavor: "chocolate"}
new OptionsInLiteral({flavor: "strawberry", sprinkles: true});
//OptionsInLiteral.initialize first argument Object {flavor: "strawberry", sprinkles: true}
//OptionsInLiteral.initialize this.options Object {flavor: "strawberry", sprinkles: true}
This will correctly take advantage of Backbone.View._configure
, which as of Backbone 1.0.0 looks like this:
_configure: function(options) {
if (this.options) options = _.extend({}, _.result(this, 'options'), options);
_.extend(this, _.pick(options, viewOptions));
this.options = options;
},
What this means is:
options
, _configure
will properly treat those as default values, override them with properties passed into the constructor, and set the final resulting object as this.options
. Hurray. That's what we want._.result
is used here, the options
property may be either an Object
or a function
, and if it's a function, it will be called and the return value will be used.This is also acceptable and allows the defaults to be unique per instance.
var OptionsFunctionInLiteral = Backbone.View.extend({
options: function () {
return {
flavor: "vanilla",
created: Date(),
collection: new Backbone.Collection()
};
},
initialize: function (options) {
console.log("OptionsFunctionInLiteral.initialize first argument", options);
console.log("OptionsFunctionInLiteral.initialize this.options", this.options);
}
});
Here are some examples and what they log to the console.
new OptionsFunctionInLiteral();
//OptionsFunctionInLiteral.initialize first argument undefined
//OptionsFunctionInLiteral.initialize this.options Object {flavor: "vanilla", created: "Wed Jun 19 2013 16:20:16 GMT-0600 (MDT)", collection: Backbone.Collection}
new OptionsFunctionInLiteral({flavor: "chocolate"});
//OptionsFunctionInLiteral.initialize first argument Object {flavor: "chocolate"}
//OptionsFunctionInLiteral.initialize this.options Object {flavor: "chocolate", created: "Wed Jun 19 2013 16:21:17 GMT-0600 (MDT)", collection: Backbone.Collection}
new OptionsFunctionInLiteral({flavor: "strawberry", sprinkles: true});
//OptionsFunctionInLiteral.initialize first argument Object {flavor: "strawberry", sprinkles: true}
//OptionsFunctionInLiteral.initialize this.options Object {flavor: "strawberry", created: "Wed Jun 19 2013 16:22:26 GMT-0600 (MDT)", collection: Backbone.Collection, sprinkles: true}
So the above is great with the caveat that if your view's constructor is called with no arguments, inside your initialize
function this.options
will exist and be correct but the plain options
argument to the initialize
function will be undefined
.
initialize: function (options) {
console.log(options.flavor); //BUG! options is undefined. Uncaught exeption. :-(
console.log(this.options); //correct
}
Thus when I define my initialize, I don't even specify the options
argument to the function as a reminder not to use it. In general you want to ignore the options
argument to initialize
because it doesn't contain the default values anyway.
This answer has a bug in that it unintentionally modifies the defaults for all future instances every time an instance is instatiated.
var DefaultsExtendView = Backbone.View.extend({
defaults: {flavor: "vanilla"},
initialize: function (options) {
console.log("initialize 1st argument", options);
this.options = _.extend(this.defaults, this.options);
console.log("initialize this.options", this.options);
}
});
new DefaultsExtendView(); //OK
new DefaultsExtendView({flavor: "chocolate"}); //OK
new DefaultsExtendView(); //BUG! You get chocolate instead of vanilla
var myView = Backbone.View.extend({
foo: "default_value",
initialize: function(options) {
if(options.foo) {
foo = options.foo;
}
}
});
new myView(); //BUG! options is undefined, uncaught exception
//TypeError: Cannot read property 'foo' of undefined
One of the answers to this question suggests this:
var DefaultsView = Backbone.View.extend({
defaults: {
collection: new Backbone.Collection()
},
initialize: function () {
_.defaults(this.options, this.defaults);
Which is almost certainly not what you want and a bug. If you make 10 views, they will all be sharing the same instance of Backbone.Collection
as there will just be 1 instance created when the view subclass is defined. This is sure to confuse you when you add a model to view9's collection and it shows up in all of the views. What you more likely want is a different new collection instance for each view instance, and to get that you need to make options
be a function as in my example above.
options: {...}
or options: function () {...}
initialize
without any argumentsthis.options
var MyView = Backbone.View.extend({
options: {flavor: "vanilla"},
initialize: function () { //note no declared arguments
//use this.options here as needed and all is well
}
});
http://jsfiddle.net/DUc25/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With