Adam Knights
Adam Knights

Reputation: 2151

Ember data show length of a hasMany relationship in a template without downloading all the objects of that relationship

I have a product model that hasMany prices. I have a page that displays the products name, code and then the number of prices it has i.e:

<tbody>
  {{#each model as |product id|}}
  <tr>
    <td>{{#link-to "product" product}}{{product.name}}{{/link-to}}</td>
    <td>{{product.code}}</td>
    <td>{{product.prices.length}}</td>
  </tr>
  {{/each}}
</tbody>

The issue I have is that by using product.price.length Ember data is making thousands of requests to get the prices by id. I don't need any information about the actual price on this page. How can I use the length property here without Ember data downloading all the prices?

models/product.js:

export default DS.Model.extend({
  code: DS.attr('string'),
  name: DS.attr('string'),
  prices: DS.hasMany('price', {async: true})
});

models/price.js

export default DS.Model.extend({
  product: DS.belongsTo('product', {async: true}),
  value: DS.attr('number'),
  minUnits: DS.attr('number'),
  maxUnits: DS.attr('number')
});

Upvotes: 5

Views: 1154

Answers (1)

Adam Knights
Adam Knights

Reputation: 2151

Having chatted in the ember slack room I have two current solutions, one backend, one frontend.

Frontend

As of Ember data 2.5 there is a new 'ds-references' feature as detailed in the release post http://emberjs.com/blog/2016/05/03/ember-data-2-5-released.html.

With this the solution here would be to add a computed with something like:

priceCount: Ember.computed('prices.[]', function() {
  if (this.hasMany('prices').value() === null) {
    return 0;
  }

  return this.hasMany('prices').ids().length;
}

It's been reported in the comments that the above may trigger backend requests. As an alternative, you could add a helper function totalHasMany with code

return param[0].hasMany(param[1]).ids().length

and use it in a template with (totalHasMany product 'prices'), I've used this in an app with success.

Backend

Look at using meta data to return the price total. So in a Json Api settings something like

"meta": {
  "prices-total": 123
}

See http://jsonapi.org/format/#document-meta for further info.

https://guides.emberjs.com/v2.1.0/models/handling-metadata/ may also be useful to those on standard json.

Thanks to kitler and locks for the above suggestions in slack.

Upvotes: 6

Related Questions