Paul Cowan

Nomadic cattle rustler and inventor of the electric lasso

ember.js - Computed Property for All Keys of an Object

I came across a situation today where I wanted to create a computed property which would recalculate itself every time one of the properties of an object changed. The lazy and tedious thing to do would have been to simply list them out like this:

long.js
1
2
3
previewHeaders: Ember.computed('headerInfo.firstName', 'headerInfo.surname', 'headerInfo.email', function(){
  //do stuff
})

This is tedious for a number of reasons but the main one is that I have to remember to update the dependent key list, every time the object changes.

Below is the solution I came up with:

just.js
1
2
3
4
5
6
7
8
9
10
11
12
App.computed.addAllKeysProperty = function(context, propertyName, objectPath, func) {
  var args, subject;
  subject = context.get(objectPath);

  args = Ember.keys(subject).map(function(key) {
    return "" + objectPath + "." + key;
  });

  args.push(func);

  return Ember.defineProperty(context, propertyName, Ember.computed.apply(this, args));
};

This is slightly more convoluted that I would have liked as I could not create a real property because I need the context argument to be an instance on line 3 so that I can call Ember.keys on this instance. Instead of creating an actual property, I use defineProperty on line 11 to create the property at runtime. I create the dependant key list by using Ember.keys to iterate over the subject’s properties and then call Ember.computed.apply to equal the call from the gist at the top of the post.

Below is the calling code:

init.js
1
2
3
4
5
6
init: function() {
  this._super.apply(this, arguments);
  return App.computed.addAllKeysProperty(this, 'previewHeaders', 'headerInfo', function() {
    //do stuff
  });
},

It is slightly dissatisfying in that I could not create an actual property and if you can suggest a better way then please leave a comment below.

Comments