Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save giiska/d8b09252e4cfa081d0e6 to your computer and use it in GitHub Desktop.
Save giiska/d8b09252e4cfa081d0e6 to your computer and use it in GitHub Desktop.
several ways to add/get/filter-when-save derived attributes for backbone model

set attributes mannuly

// Cons: make code too redundant
var MyModel = Backbone.Model.extend({
    initialize: function() {
        this.updateDerivedAttributes();
        this.on('change:start_at', this.updateDerivedAttributes, this);
    },
    updateDerivedAttributes: function() {
        this.set({
            start_date: Utils.dateFromDate( this.get( "start_at" ) ),
            start_time: Utils.timeFromDate( this.get( "start_at" ) ),
            duration: Utils.youGetTheIdea()
        }, {silent:true});
    }


  // override `toJSON` method

  // set viewOnlyAttrs for attributes no need to save
  viewOnlyAttrs: ['start_date', 'start_time', 'duration'],

  toJSON: function(options) {
    var obj = this;

    // if is calling from model's save method
    if(_.has(options || {}, 'emulateHTTP') && obj.viewOnlyAttrs)
      return _.omit(obj.attributes, obj.viewOnlyAttrs);

    return Backbone.Model.prototype.toJSON.call(this, options);
  }
})

new method to get and toJSON

wrapper toJSON method to get all attributes include derived attributes

Cons: cannot get derived attribute by model's get method, and is not work well with collection as collection call model's toJSON not toJSONDecorated

toJSONDecorated: function() {
  return 
    _.extend( 
      this.toJSON(), 
      {
        start_date : Utils.dateFromDate( this.get( "start_at" ) ),
        start_time : Utils.timeFromDate( this.get( "start_at" ) ),
        duration   : Utils.youGetTheIdea( :) )
      } 
    );
}

new method to get 'derived attribute'

In fact, these are not derived attributes

Cons: if want to get these attributes in view template, you cannot use model's toJSON method, instead, feed model instance in it

getUrl: function() {
  return 'urlPrefix/' + this.get('id');
}

computed properties

set computed attributes by defaults

var MyModel = BaseModel.extend({
    defaults: {
        avg: function(){
            return (this.get('min') + this.get('max')) / 2;
        }
    }
});
// need to override `get` and `toJSON` methods
Backbone.Model.extend({
  get: function(attr) {
    var value = Backbone.Model.prototype.get.call(this, attr);
    return _.isFunction(value) ? value.call(this) : value;
  },
  toJSON: function(options) {
    var data = {};
    
    var json = Backbone.Model.prototype.toJSON.call(this);

    _.each(json, function(value, key) {
      // filter isFunction value if is calling from model's save method
      if(!_.has(options || {}, 'emulateHTTP') || !_.isFunction(value))
        data[key] = this.get(key);
    }, this);

    return data;
  }
});

use new object to store computed attributes

See detail at Backbone.Mutators plugin

var User = Backbone.Model.extend({
    // Define mutator properties
    mutators: {
        fullname: function () {
            return this.get('firstname') + ' ' + this.get('lastname');
        }
    },
    defaults: {
        firstname: 'Sugar',
        lastname: 'Daddy'
    }
 });

 var user = new User();
 // use get to get the 'mutated' value
 user.get('fullname') // 'Sugar Daddy'
 // serialize the model and see the 'mutated' value in the resulting JSON
 user.toJSON() // '{firstname: 'Sugar', lastname: 'Daddy', fullname: 'Sugar Daddy'}'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment