Conditional Default Values for Ember Data Model Attributes

May 26, 2018

When defining attributes on Ember Data models, you can specify a default value through the second argument to DS.attr():

// models/metric-selection.js
import DS from 'ember-data';

const { Model, attr, belongsTo } = DS;

export default Model.extend({
  unit: attr('string', { defaultValue: 'GB' }),
  metric: belongsTo('metric', { async: false })
});

The defaultValue option can also be a function. This can be useful for when you want the default value of an attribute to be an object.

// models/user.js
import DS from 'ember-data';

const { Model, attr } = DS;

export default Model.extend({
  preferences: attr({
    defaultValue() {
      return {};
    }
  })
});

If we didn’t use a function here for defaultValue, all user instances would reference the same object, which usually isn’t the desired behavior.

Using a function for defaultValue can also be useful to conditionally set a default value. Although not documented at the time of this writing, I recently discovered that the first parameter passed to the defaultValue function is the instance of a model. This can be used to conditionally set the default value based on other attributes or relationships. For example:

// models/metric-selection.js
import DS from 'ember-data';

const { Model, attr, belongsTo } = DS;

export default Model.extend({
  unit: attr('string', {
    defaultValue(metricSelection) {
      if (metricSelection.get('metric.type') === 'usage') {
        return 'GB';
      } else {
        return null;
      }
    }
  }),
  metric: belongsTo('metric', { async: false })
});

In an analytics reporting application I am working on, users can select multiple metrics and specify a unit for some of those metrics for how they want to see the data in their report. In the code above, there is a model called metric-selection, which has a unit string attribute and a metric relationship. The default value of unit is determined based on metric, which can be accessed off of metricSelection, the metric-selection instance, passed to the defaultValue function.

Thanks to @runspired for confirming that it is part of public API that the defaultValue function receives an instance of the model as its first parameter.

Disclaimer: Any viewpoints and opinions expressed in this article are those of David Tang and do not reflect those of my employer or any of my colleagues.