Sapan Diwakar

Software developer

Follow me on Twitter Check out my code on GitHub View some of my designs on Dribbble Take a look at my Linked In profile

Dynamically adding attributes to an Ember Data Model

Often times, you want to add some attributes to an Ember Data model dynamically (e.g. you might want a translateable attribute for each available locale). Lets say, you have a name attribute that you want to translate in English, Spanish, French and Chinese. Here's how you would usually write it:

App.Product = DS.Model.extend({  
  nameEn: DS.attr('string'),
  nameEs: DS.attr('string'),
  nameFr: DS.attr('string'),
  nameZh: DS.attr('string')
});

While this might be ok for a few locales, but consider doing this for a large number of locales. This is too much work!

Since, all we need to pass to DS.Model.extend is a JavaScript object, to support multiple attributes, all we need is to create the object dynamically based on the available locales before passing it on. Here's a very simple function (using Combinatorics and _) that creates an object with propertyNameLocale : DS.attr(...) pairs for each property and locale.

/**
 * Creates an object with propertyNameLocale : DS.attr(...) for each property and locale
 * @param properties
 * @returns {*}
 */
translatedModelProperties: function (properties) {  
  return $.extend.apply($, _.flatten([
    {},
    Combinatorics.cartesianProduct(_.keys(properties), App.get('locales')).toArray().map(function (localePropertyNameArray) {
      var propertyName = localePropertyNameArray[0];
      return _.object([localePropertyNameArray.join('_').camelize()], [properties[propertyName]]);
    })
  ]));
}

All you need now is to use it to super charge your models and you are done. No more duplication for every translatable property, Yay!

App.Product = DS.Model.extend($.extend({  
  // Non translated properties
  price: DS.attr('number')
}, App.translatedModelProperties({
  // Translatable properties
  name: DS.attr('string')
})))