Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <h1>For Backbone 1.1 or newer</h1> <h2>Approach A: OptionsInLiteral with _.defaults in initialize</h2> <pre><code>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); } }); </code></pre> <h2>Approach B: Use the viewOptions plugin (or similar)</h2> <p><a href="https://github.com/rotundasoftware/backbone.viewOptions" rel="nofollow">backbone.viewOptions</a></p> <p>Thanks to @BraveDave for pointing this out in a comment.</p> <h1>For Backbone prior to version 1.1 (historical reference, FYI)</h1> <p><a href="https://github.com/documentcloud/backbone/issues/2458#issuecomment-15991661" rel="nofollow">Here is the backbone issue</a> where it seems like the core team is most likely to get rid of <code>this.options</code> and the logic in <code>_configure</code> altogether.</p> <h2>Use an options property and always use this.options</h2> <p>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.</p> <p>To work in harmony with the <code>Backbone.View</code> parent class, you are supposed to include an <code>options</code> property of the object literal you pass to <code>Backbone.View.extend</code>.</p> <pre><code>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); } }); </code></pre> <p>Here are some examples and what they log to the console.</p> <pre><code>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} </code></pre> <p>This will correctly take advantage of <code>Backbone.View._configure</code>, which as of Backbone 1.0.0 looks like this:</p> <pre><code>_configure: function(options) { if (this.options) options = _.extend({}, _.result(this, 'options'), options); _.extend(this, _.pick(options, viewOptions)); this.options = options; }, </code></pre> <p>What this means is:</p> <ul> <li>If your view object literal contains <code>options</code>, <code>_configure</code> will properly treat those as default values, override them with properties passed into the constructor, and set the final resulting object as <code>this.options</code>. Hurray. That's what we want.</li> <li>This will work even if the view constructor is invoked without arguments. Hurray. Also what we want.</li> <li>Because <code>_.result</code> is used here, the <code>options</code> property may be either an <code>Object</code> or a <code>function</code>, and if it's a function, it will be called and the return value will be used.</li> </ul> <p>This is also acceptable and allows the defaults to be unique per instance.</p> <pre><code>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); } }); </code></pre> <p>Here are some examples and what they log to the console.</p> <pre><code>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} </code></pre> <h3>Why you should always use this.options</h3> <p>So the above is great with the caveat that if your view's constructor is called with no arguments, inside your <code>initialize</code> function <code>this.options</code> will exist and be correct but the plain <code>options</code> argument to the <code>initialize</code> function will be <code>undefined</code>.</p> <pre><code>initialize: function (options) { console.log(options.flavor); //BUG! options is undefined. Uncaught exeption. :-( console.log(this.options); //correct } </code></pre> <p>Thus when I define my initialize, I don't even specify the <code>options</code> argument to the function as a reminder not to use it. In general you want to ignore the <code>options</code> argument to <code>initialize</code> because it doesn't contain the default values anyway.</p> <h2>Buggy answer: _.extend(this.defaults, this.options)</h2> <p>This answer has a bug in that it unintentionally modifies the defaults for all future instances every time an instance is instatiated.</p> <pre><code>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 </code></pre> <h2>Buggy answer: if (options.foo)</h2> <pre><code>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 </code></pre> <h2>Beware of options object and instance-specific defaults</h2> <p>One of the answers to this question suggests this:</p> <pre><code>var DefaultsView = Backbone.View.extend({ defaults: { collection: new Backbone.Collection() }, initialize: function () { _.defaults(this.options, this.defaults); </code></pre> <p>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 <code>Backbone.Collection</code> 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 <code>options</code> be a function as in my example above.</p> <h2>Summary of the proper way to do this</h2> <ol> <li>use <code>options: {...}</code> or <code>options: function () {...}</code></li> <li>Declare your <code>initialize</code> without any arguments</li> <li>Access your properly-defaulted options as <code>this.options</code></li> </ol> <h2>Example Boilerplate</h2> <pre><code>var MyView = Backbone.View.extend({ options: {flavor: "vanilla"}, initialize: function () { //note no declared arguments //use this.options here as needed and all is well } }); </code></pre> <h2>Working jsfiddle</h2> <p><a href="http://jsfiddle.net/DUc25/" rel="nofollow">http://jsfiddle.net/DUc25/</a></p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload