Wednesday, July 2, 2014

Backbone: How To Define Model Properties

Backbone models are kind of like plain JavaScript objects in that they have attribute names mapped to attribute values. In fact, you generally instantiate models by passing in a plain JavaScript object to the constructor. The difference, however, is in how you read and write Backbone model attributes. There's the set() and the get() method — an indirection not exhibited by plain objects.

With a little hackery, I was able to implement a simple work-around for accessing Backbone model attribute values directly, without resorting to the get() method. Or the attributes object. This feels more natural, and is especially helpful when I need the attribute value often, and don't always want to call toJSON().

var MyModel = Backbone.Model.extend({
    
    defaults: {
        attr1: 'val1',
        attr2: 'val2',
        attr3: 'val3'
    },
    
    initialize: function() {
        _( this.attributes )
            .keys()
            .each( function( i ) {
                Object.defineProperty( this, i, {
                    get: _.partial( this.get, i )
                });
            }, this );
    }
    
});

var model = new MyModel();
console.log(model.attr1);

This only takes a few lines to accomplish. In the model constructor — initialize() — I'm iterating over the attribute keys. For each key name, I use Object.defineProperty() to make a new property directly on the model. This is the thing I want to access later on without resorting to get() or attributes. The new property uses the get() method internally, we just have to wrap it in a partial — using the property name as the default argument.