5

model:

DS.Model.extend({
  title: DS.attr('string'),
  body: DS.attr('string'),
  comments: DS.hasMany('comment', { async: true} ),

  hasComments: Ember.computed.gt('comments.length', 0)
});

payload:

{ 
  "id": "abcdefg",
  "title": "some cats are cool",
  "body": "",
  "comments: ["100", "101", "102"]
}

But the hasComments computed property triggers a fetch for each comment individually.. I don't want this :D

I know this works (avoids the fetch), but reaches into private API:

hasComments: Ember.computed.gt('data.comments.length', 0)

ember.js 1.8.1

ember-data 1.0.0-beta.11

Any other recommendations on achieving a computed property based off of the length

Community
  • 1
  • 1
Joe B
  • 1,261
  • 14
  • 20

3 Answers3

6

As of Ember Data 2.5 (mentioned in release notes) there is a feature called ds-references which provides a way to check if if a hasMany relationship contains items or not without triggering a fetch for those items:

export default Model.extend({
  title: DS.attr('string'),
  body: DS.attr('string'),
  comments: DS.hasMany('comment', { async: true} ),

  hasComments: Ember.computed('comments', function() {
    return this.hasMany('comments').ids().length > 0;
  })
});

See this working in an Ember Twiddle

The ds-references feature implements the references API as described in RFC 57. References is a low level API to perform meta-operations on records, has-many relationships and belongs-to relationships:

  • get the current local data synchronously without triggering a fetch or producing a promise
  • notify the store that a fetch for a given record has begun, and provide a promise for its result
  • similarly, notify a record that a fetch for a given relationship has begun, and provide a promise for its result
  • retrieve server-provided metadata about a record or relationship

Source: Ember forum post and Ember Data 2.5 release blog post

real_ate
  • 10,861
  • 3
  • 27
  • 48
CraigTeegarden
  • 8,173
  • 8
  • 38
  • 43
0

You mentioned, that each comment was fetched individually. This can be avoided by setting coalesceFindRequests on the RestAdapter, if your backend supports this.

Yet, you'd still have one request too many. I don't think, that that can be avoided without some kind of dirty trick, but am open to learn from other answers.

jnfingerle
  • 713
  • 4
  • 16
  • Thanks for sharing that tip. Turns out there is an open issue on github. Added comment to my question with direct link. – Joe B May 05 '15 at 16:47
0

I wish there was an easy way to do this. The simplest way I can think of is to override extractHasMany in your serializer and save a new property, commentsCount, on your model, eg:

models/post.rb:

DS.Model.extend({
  title: DS.attr('string'),
  body: DS.attr('string'),
  comments: DS.hasMany('comment', { async: true} ),
  commentsCount: DS.attr('number'),

  hasComments: Ember.computed.gt('commentsCount', 0)
});

serializers/post.rb:

export default ApplicationSerializer.extend({
  normalizeHash: {
    posts(hash) {
      hash.comments_count = hash.comments.length;
      return hash;
    }
  }
}

Be careful though, as the commentsCount property will not automatically recompute in this case when you add/remove comments. You could probably build a computed property that uses the actually comments instead of commentsCount if the comments are loaded.

stephen.hanson
  • 9,014
  • 2
  • 47
  • 53
  • thanks for sharing that work around! Everything I've uncovered points to code like yours. Another example I've run across, https://github.com/emberjs/rfcs/pull/57#issuecomment-121008369 – Joe B Aug 11 '15 at 15:09