javascriptember.jsember-data

How to detect if included relationship is loading


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


Solution

    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