How to detect if included relationship is loading

Viewed 95

Please see related twiddle https://ember-twiddle.com/e3872f1410e0d844b6d6c6bc9a2c9dc1

// models/parent.js
export default class extends Model {
  @attr('string') name;
  @hasMany('child') children;
}

// models/child.js
export default class extends Model {
  @attr('string') name;
}
// routes/application.js
export default Route.extend({
  model() {
    return this.store.findAll('parent');
  }
});

// routes/second-route.js
export default Route.extend({
  model(params) {
    return this.store.findRecord('parent', params.parent_id, { 
      include: 'children'
    });
  }
});
//templates/application.hbs
{{#each this.model as |parent|}}
  <div>{{parent.name}}</div>
  <LinkTo @route="second-route" @model={{parent.id}}>
    Go to second route with this model
  </LinkTo>
{{/each}}

{{outlet}}

//templates/second-route.hbs
{{#each this.model.children as |child|}}
  <div>{{child.name}}</div>
  {{else}}
  <div>Nothing to display</div>
{{/each}}

In the ember twiddle

  1. Click link to transition to second route
  2. Observe second route displays "Nothing to display"
  3. After 2 seconds, when the request completes, the template will update to display the hasMany models

I would have expected that the template is only rendered after the request to /parents/1 completes, but this is not the case

  1. Why does the template not wait for the route's model?
  2. How can I improve UX by detecting that the hasMany relationships are loading to display a loading indicator?

Flags on the promise proxies do not seem to change at any point

1 Answers
  1. The template does not wait because the promise immediately resolves because the record is found in the store.

  2. I do wish there were a better api, but I forked your twiddle and show a solution: https://ember-twiddle.com/af0a823fc73474db1c09083c429fef4f?openFiles=models.parent%5C.js%2C&route=%2Fsecond-route%2F1

The essential code is this:

// app/model/parent.js

get childrenLoading() {
    return this.hasMany('children').load().isPending;
}

this.hasMany('...') is a low level Ember Data api that returns a relationship reference. The load() method causes it to load if it isn't already, but more importantly, returns a promise that will resolve when the relationship is loaded.

You can read more about the HasManyReference class in the api

Related