Skip to content

Instantly share code, notes, and snippets.

@tjbladez
Created May 8, 2012 17:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tjbladez/2637522 to your computer and use it in GitHub Desktop.
Save tjbladez/2637522 to your computer and use it in GitHub Desktop.
basic computed properties in backbone
Namespace.models.Base = Backbone.Model.extend
initialize: ()->
Backbone.Model::initialize @, arguments
return if _.isUndefined(@computed)
@_computed = {}
for attr, dependencies of @computed
@on "change:#{attr}", ()=>
@_computed[attr] = @[attr].call @
_(dependencies).each (dep)=>
@on "change:#{dep}", ()=>
@trigger "change:#{attr}"
@trigger "change:#{attr}" if @has(dep)
get: (attr)->
if @computed?.hasOwnProperty(attr)
@_computed[attr]
else
Backbone.Model::get.call @, attr
Namespace.models.Example = Namespace.models.Base.extend
computed:
fullName: ['firstName', 'lastName']
fullName: ()->
"#{@get('firstName')} #{@get('lastName')}"
@uzikilon
Copy link

uzikilon commented May 8, 2012

I'm no a CS guy, so i converted this to javascript.
This doesn't make a lot of sense:

// Generated by CoffeeScript 1.3.1
(function() {

  Namespace.models.Base = Backbone.Model.extend({
    initialize: function() {
      var attr, dependencies, _ref, _results,
        _this = this;
      Backbone.Model.prototype.initialize(this, arguments);
      if (_.isUndefined(this.computed)) {
        return;
      }
      _ref = this.computed;
      _results = [];
      for (attr in _ref) {
        dependencies = _ref[attr];
        this.on("change:" + attr, function() {
          var param;
          param = {};
          param["_" + attr] = _this[attr].call(_this);
          return _this.set(param);
        });
        _results.push(_(dependencies).each(function(dep) {
          return _this.on("change:" + dep, function() {
            return _this.trigger("change:" + attr);
          });
        }));
      }
      return _results;
    },
    get: function(attr) {
      var _ref;
      if ((_ref = this.computed) != null ? _ref.hasOwnProperty(attr) : void 0) {
        attr = "_" + attr;
      }
      return Backbone.Model.prototype.get.call(this, attr);
    }
  });

  Namespace.models.Example = Namespace.models.Base.extend({
    computed: {
      fullName: ['firstName', 'lastName']
    },
    fullName: function() {
      return "" + (this.get('firstName')) + " " + (this.get('lastName'));
    }
  });

}).call(this);

@tjbladez
Copy link
Author

tjbladez commented May 8, 2012

Can you please elaborate?
Here is working fiddle example if you want to fiddle with it: http://jsfiddle.net/Cpn3g/247/
Update: To support initial setting of the models via constructor http://jsfiddle.net/Cpn3g/250/

@uzikilon
Copy link

uzikilon commented May 8, 2012

There are many ways to do it, it's all about pros, cons and personal preferences - to me this seems more complex and doesn't add much value.
I'm not suggesting it doesn't work, however there are a bunch of issues with it:

  • Changing the convention of a model (adding extra methods) is something i try to avoid (smells like home brew).
  • Adding extra model properties with trailing underscore can have side effects.
  • This will throw when you try to `model.set({fullName: 'some random name'});
  • In general, I think events are a non issue and we should not bind to computed properties events

@tjbladez
Copy link
Author

tjbladez commented May 9, 2012

Cool, thanks

@curran
Copy link

curran commented Mar 24, 2014

Greetings,

Here is a small function that implements computed properties for Backbone https://github.com/curran/backboneComputedProperties .

Regards,
Curran

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment