lowerkey
lowerkey

Reputation: 8345

backbone.js model inheritance

I have a backbone model

var app = app || {};

app.Era = Backbone.Model.extend({

    defaults: {
        from: Number.NEGATIVE_INFINITY,
        until: Number.POSITIVE_INFINITY,
        stash: {
            from: null,
            until: null
        },
        _enabled: true
    },

    toggle: function(){
        if(this.get('_enabled')){
            this.disable();
        }else{
            this.enable();
        }

        this.save();
    },

    enable: function(){
        this.from = this.stash.from;
        this.until = this.stash.until;

        this.stash.from = null; // strictly speaking unnecssary
        this.stash.until = null;

        this._enabled = true;
    },

    disable: function(){
        this.stash.from = this.from;
        this.stash.until = this.until;

        this.from = null;
        this.until = null;

        this._enabled = false;
    },

    enabled: function(){
        return this._enabled;
    },

});

which I'm trying to extend like so

Name = app.Era.extend({ defaults: { value: '' } });

This seems to work, I get no error in the console. I can even instantiate a new Name, but when I try to instantiate a new Name, I get an Error message:

> era = new app.Era()
child
> era.get('from')
-Infinity
> Name = app.Era.extend({ defaults: { value: '' } })
function (){ return parent.apply(this, arguments); }
> name = new Name()
child
> name.get('value')
TypeError: Object [object Object] has no method 'get'

I'd be grateful of some feedback!

Upvotes: 3

Views: 3122

Answers (2)

jevakallio
jevakallio

Reputation: 35970

Edit: This might very well be a decent answer, but not to this particular question... The correct answer was provided by Bryan Clark. I'll leave this here regardless, because while I misunderstood your question, it describes a solution to a common problem and may help you anyway.

Backbone inheritance works by modifying the constructor function's prototype. When you extend a model and redefine the defaults property, it doesn't merge the Name.defaults property to Era.defaults, but simply hides it.

Consider a simplified example:

var Era = Backbone.Model.extend({ name: "Era" });
var Name = Era.extend({ name: "Name" });
console.log(new Name().name); //-> "name", makes sense, right?

To merge the derived class defaults to the superclass's, you can take advantage of the fact that Model.defaults can be defined as a function as well as an object literal.

var Era = Backbone.Model.extend({ 
  defaults: {
    //..
  } 
});

var Name = Era.extend({ 
  //define defaults as a function
  defaults: function() {
    //copy the superclass defaults into a new object, and
    //then extend that with the new defaults
    return _.extend({}, Era.prototype.defaults, {
      value:''
    });
  }
});

Upvotes: 10

Bryan Clark
Bryan Clark

Reputation: 2602

You can't use name in that context, you're running into window.name. If you start from scratch without the lowercase name variable you should run just fine. Also, fencliff makes good points in how to use default inheritance.

Upvotes: 3

Related Questions