Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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')
});
like image 894
Adam Knights Avatar asked Feb 15 '16 09:02

Adam Knights


1 Answers

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.

like image 81
Adam Knights Avatar answered Sep 18 '22 13:09

Adam Knights