Simon Frost
Simon Frost

Reputation: 171

Setting default as local variable in model results in undefined

When I run the code below the default trackName and artistName is set as 'undefined'

window.TrackDetailsModel = Backbone.Model.extend({
  NO_TRACK: 'No Track Set.',
  NO_ARTIST: 'No Artist Set.',

  defaults: {
    squareNumber: -1,
    trackName: this.NO_TRACK,
    artistName: this.NO_ARTIST,
    albumArt: './img/default.png'
  },

I can fix this by manually setting the variable in the initialize method, but I would prefer to set it in the defaults

  initialize: function() {
    this.set('trackName', this.NO_TRACK);
    this.set('artistName', this.NO_ARTIST);
  },

Is the local variable not set before the defaults section accesses it? Or should I be using something other than 'this' for accessing this.NO_TRACK

Upvotes: 0

Views: 39

Answers (2)

James Hay
James Hay

Reputation: 7315

The object you are passing to the Backbone.Model.extend method

{
   NO_TRACK: 'No Track Set.',
   NO_ARTIST: 'No Artist Set.',
   defaults: {
       squareNumber: -1,
       trackName: this.NO_TRACK,
       artistName: this.NO_ARTIST,
       albumArt: './img/default.png'
}

Has a different context of this. The this object does not apply to the extended backbone model yet, but instead applies to the context in which you are extending the model.

Example

var foo = {
    value: 'something',
    fn: function() {
       window.TrackDetailsModel = Backbone.Model.extend({
           NO_TRACK: 'No Track Set.',
           NO_ARTIST: 'No Artist Set.',

           defaults: {
              squareNumber: -1,
              trackName: this.NO_TRACK,
              artistName: this.NO_ARTIST,
              albumArt: './img/default.png'
           }
       });
    }
}

foo.fn();

When the foo.fn() is called, any this value inside the immediate function applies to foo itself. So you're actually saying foo.NO_TRACK which as you can see does not exists. But if you said artistName: this.value then it would correctly assign the "something" for the artist name

If this is not part of a variable (that is to say, it's called in the global scope) then the value of this will be the window object, so you're actually saying window.NO_TRACK

A solution to your problem may look something like this:

var d = {
    squareNumber: -1,
    trackName: 'No Track Set.',
    artistName: 'No Artist Set.',
    albumArt: './img/default.png'
}

window.TrackDetailsModel = Backbone.Model.extend({
    NO_TRACK: d.trackName,
    NO_ARTIST: d.artistName,
    defaults: d
});

However from a logical view of what you're acheiving, your manual method of setting those values on initialization seems the most correct way of doing it. "When an instance of the model is first created, initialize the track name and artist name to these values.."

Upvotes: 2

Ram
Ram

Reputation: 144689

You can't do that. Object literals do not create a new scope so this doesn't refer to the current model, it refers to another object which doesn't have 'NO_TRACK' property. You have to set the value in your initialize method or create a base model and extend that instead.

Upvotes: 1

Related Questions