Class DS

Module: ember-data

All Ember Data classes, methods and functions are defined inside of this namespace.

Show:

type
String|Object
the attribute type
options
Object
a hash of options
returns
Attribute

DS.attr defines an attribute on a DS.Model. By default, attributes are passed through as-is, however you can specify an optional type to have the value automatically transformed. Ember Data ships with four basic transform types: string, number, boolean and date. You can define your own transforms by subclassing DS.Transform.

Note that you cannot use attr to define an attribute of id.

DS.attr takes an optional hash as a second parameter, currently supported options are:

  • defaultValue: Pass a string or a function to be called to set the attribute to a default value if none is supplied.

Example

app/models/user.js
1
2
3
4
5
6
7
import DS from 'ember-data';

export default DS.Model.extend({
  username: DS.attr('string'),
  email: DS.attr('string'),
  verified: DS.attr('boolean', { defaultValue: false })
});

Default value can also be a function. This is useful it you want to return a new object for each attribute.

app/models/user.js
1
2
3
4
5
6
7
8
9
10
11
import DS from 'ember-data';

export default DS.Model.extend({
  username: DS.attr('string'),
  email: DS.attr('string'),
  settings: DS.attr({
    defaultValue() {
      return {};
    }
  })
});

The options hash is passed as second argument to a transforms' serialize and deserialize method. This allows to configure a transformation and adapt the corresponding value, based on the config:

app/models/post.js
1
2
3
4
5
6
7
import DS from 'ember-data';

export default DS.Model.extend({
  text: DS.attr('text', {
    uppercase: true
  })
});
app/transforms/text.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import DS from 'ember-data';

export default DS.Transform.extend({
  serialize(value, options) {
    if (options.uppercase) {
      return value.toUpperCase();
    }

    return value;
  },

  deserialize(value) {
    return value;
  }
})
modelName
String
(optional) type of the relationship
options
Object
(optional) a hash of options
returns
Ember.computed
relationship

DS.belongsTo is used to define One-To-One and One-To-Many relationships on a DS.Model.

DS.belongsTo takes an optional hash as a second parameter, currently supported options are:

  • async: A boolean value used to explicitly declare this to be an async relationship.
  • inverse: A string used to identify the inverse property on a related model in a One-To-Many relationship. See Explicit Inverses

One-To-One

To declare a one-to-one relationship between two models, use DS.belongsTo:

app/models/user.js
1
2
3
4
5
import DS from 'ember-data';

export default DS.Model.extend({
  profile: DS.belongsTo('profile')
});
app/models/profile.js
1
2
3
4
5
import DS from 'ember-data';

export default DS.Model.extend({
  user: DS.belongsTo('user')
});

One-To-Many

To declare a one-to-many relationship between two models, use DS.belongsTo in combination with DS.hasMany, like this:

app/models/post.js
1
2
3
4
5
import DS from 'ember-data';

export default DS.Model.extend({
  comments: DS.hasMany('comment')
});
app/models/comment.js
1
2
3
4
5
import DS from 'ember-data';

export default DS.Model.extend({
  post: DS.belongsTo('post')
});

You can avoid passing a string as the first parameter. In that case Ember Data will infer the type from the key name.

app/models/comment.js
1
2
3
4
5
import DS from 'ember-data';

export default DS.Model.extend({
  post: DS.belongsTo()
});

will lookup for a Post type.

errors
Array
array of errors in JSON-API format
returns
Object

Convert an array of errors in JSON-API format into an object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import DS from 'ember-data';

const { errorsArrayToHash } = DS;

let errorsArray = [
  {
    title: 'Invalid Attribute',
    detail: 'Must be present',
    source: { pointer: '/data/attributes/name' }
  },
  {
    title: 'Invalid Attribute',
    detail: 'Must be present',
    source: { pointer: '/data/attributes/age' }
  },
  {
    title: 'Invalid Attribute',
    detail: 'Must be a number',
    source: { pointer: '/data/attributes/age' }
  }
];

let errors = errorsArrayToHash(errorsArray);
// {
//   "name": ["Must be present"],
//   "age":  ["Must be present", "must be a number"]
// }
errors
Object
hash with errors as properties
returns
Array
array of errors in JSON-API format

Convert an hash of errors into an array with errors in JSON-API format.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import DS from 'ember-data';

const { errorsHashToArray } = DS;

let errors = {
  base: 'Invalid attributes on saving this record',
  name: 'Must be present',
  age: ['Must be present', 'Must be a number']
};

let errorsArray = errorsHashToArray(errors);
// [
//   {
//     title: "Invalid Document",
//     detail: "Invalid attributes on saving this record",
//     source: { pointer: "/data" }
//   },
//   {
//     title: "Invalid Attribute",
//     detail: "Must be present",
//     source: { pointer: "/data/attributes/name" }
//   },
//   {
//     title: "Invalid Attribute",
//     detail: "Must be present",
//     source: { pointer: "/data/attributes/age" }
//   },
//   {
//     title: "Invalid Attribute",
//     detail: "Must be a number",
//     source: { pointer: "/data/attributes/age" }
//   }
// ]
type
String
(optional) type of the relationship
options
Object
(optional) a hash of options
returns
Ember.computed
relationship

DS.hasMany is used to define One-To-Many and Many-To-Many relationships on a DS.Model.

DS.hasMany takes an optional hash as a second parameter, currently supported options are:

  • async: A boolean value used to explicitly declare this to be an async relationship.
  • inverse: A string used to identify the inverse property on a related model.

One-To-Many

To declare a one-to-many relationship between two models, use DS.belongsTo in combination with DS.hasMany, like this:

app/models/post.js
1
2
3
4
5
import DS from 'ember-data';

export default DS.Model.extend({
  comments: DS.hasMany('comment')
});
app/models/comment.js
1
2
3
4
5
import DS from 'ember-data';

export default DS.Model.extend({
  post: DS.belongsTo('post')
});

Many-To-Many

To declare a many-to-many relationship between two models, use DS.hasMany:

app/models/post.js
1
2
3
4
5
import DS from 'ember-data';

export default DS.Model.extend({
  tags: DS.hasMany('tag')
});
app/models/tag.js
1
2
3
4
5
import DS from 'ember-data';

export default DS.Model.extend({
  posts: DS.hasMany('post')
});

You can avoid passing a string as the first parameter. In that case Ember Data will infer the type from the singularized key name.

app/models/post.js
1
2
3
4
5
import DS from 'ember-data';

export default DS.Model.extend({
  tags: DS.hasMany()
});

will lookup for a Tag type.

Explicit Inverses

Ember Data will do its best to discover which relationships map to one another. In the one-to-many code above, for example, Ember Data can figure out that changing the comments relationship should update the post relationship on the inverse because post is the only relationship to that model.

However, sometimes you may have multiple belongsTo/hasMany for the same type. You can specify which property on the related model is the inverse using DS.hasMany's inverse option:

app/models/comment.js
1
2
3
4
5
6
7
8
import DS from 'ember-data';

export default DS.Model.extend({
  onePost: DS.belongsTo('post'),
  twoPost: DS.belongsTo('post'),
  redPost: DS.belongsTo('post'),
  bluePost: DS.belongsTo('post')
});
app/models/post.js
1
2
3
4
5
6
7
import DS from 'ember-data';

export default DS.Model.extend({
  comments: DS.hasMany('comment', {
    inverse: 'redPost'
  })
});

You can also specify an inverse on a belongsTo, which works how you'd expect.

returns
String
The link Ember Data will use to fetch or reload this belongs-to relationship.

The link Ember Data will use to fetch or reload this belongs-to relationship.

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 // models/blog.js
 export default DS.Model.extend({
   user: DS.belongsTo({ async: true })
 });

 let blog = store.push({
   data: {
     type: 'blog',
     id: 1,
     relationships: {
       user: {
         links: {
           related: '/articles/1/author'
         }
       }
     }
   }
 });
 let userRef = blog.belongsTo('user');

 // get the identifier of the reference
 if (userRef.remoteType() === "link") {
   let link = userRef.link();
 }
returns
Object
The meta information for the belongs-to relationship.

The meta data for the belongs-to relationship.

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 // models/blog.js
 export default DS.Model.extend({
   user: DS.belongsTo({ async: true })
 });

 let blog = store.push({
   data: {
     type: 'blog',
     id: 1,
     relationships: {
       user: {
         links: {
           related: {
             href: '/articles/1/author',
             meta: {
               lastUpdated: 1458014400000
             }
           }
         }
       }
     }
   }
 });

 let userRef = blog.belongsTo('user');

 userRef.meta() // { lastUpdated: 1458014400000 }
modelName
String
returns
String
normalizedModelName

This method normalizes a modelName into the format Ember Data uses internally.

returns
String
The name of the remote type. This should either be "link" or "ids"

This returns a string that represents how the reference will be looked up when it is loaded. If the relationship has a link it will use the "link" otherwise it defaults to "id".

Example

app/models/post.js
1
2
3
export default DS.Model.extend({
  comments: DS.hasMany({ async: true })
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let post = store.push({
  data: {
    type: 'post',
    id: 1,
    relationships: {
      comments: {
        data: [{ type: 'comment', id: 1 }]
      }
    }
  }
});

let commentsRef = post.hasMany('comments');

// get the identifier of the reference
if (commentsRef.remoteType() === "ids") {
  let ids = commentsRef.ids();
} else if (commentsRef.remoteType() === "link") {
  let link = commentsRef.link();
}