vendredi 23 juin 2017

How do I properly display properties of deeply nested relationships in templates when using Ember Data and JSON API's include feature?

I've been attempting to take advantage of the { include: 'level1,level1.level2,level1.level2.level3' } option with Ember Data's find and query methods to load data in my route's model hooks. but as I understand it the route only pauses on the first level of data's Promise and all hasMany and belongsTo relationships have a chance to reach template code unfulfilled, and the template won't update once properties of those relationships do fulfilled.

I have a router like:

Router.map(function() {
  this.route('users', { path: '/' }, function() {
    this.route('user', { path: '/:user_id' });
  });
});

a User route:

export default Ember.Route.extend({
  model(params) {
    return this.store.findRecord('user', params.user_id, { include: 'gifts,gifts.given_by,gifts.occasion.arranged_by' });
  }
});

a User model:

export default DS.Model.extend({
  name: DS.attr('string'),
  gifts: DS.hasMany('gift', { inverse: 'givenTo' })
});

a Gift model:

export default DS.Model.extend({
  name: DS.attr('string'),
  givenBy: DS.belongsTo('user'),
  givenTo: DS.belongsTo('user'),
  occasion: DS.belongsTo('occasion')
});

an Occasion model:

export default DS.Model.extend({
  name: DS.attr('string'),
  location: DS.belongsTo('location'),
  giftsGiven: DS.hasMany('gift')
});

a Location model:

export default DS.Model.extend({
  name: DS.attr('string'),
  occasions: DS.hasMany('occasion')
});

So for example, I have many levels of relationships I'm loading and wanting to use in my User template as part of the User's profile. In my User template I want to list in a table the Gifts the user has been given and related information like.

<h1>'s Gifts
<thead>
  <tr>
    <th>Gift Name</th>
    <th>Given By</th>
    <th>Occasion</th>
    <th>Where</th>
  </tr>
</thead>
<tbody>
  
    <tr>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
  
</tbody>

Let's say 10 gifts were returned from the database so the table is 10 rows long. What I'd expect to see is a fully populated table, what I see instead, consistent between page refreshes is the following:

╔═══════════╦══════════╦══════════╦══════════╗
║ Gift Name ║ Given By ║ Occasion ║  Where   ║
╠═══════════╬══════════╬══════════╬══════════╣
║ Present 1 ║ Friend 1 ║ Birthday ║ The Park ║
║ Present 1 ║ Friend 1 ║ Birthday ║ The Park ║
║ Present 1 ║ Friend 1 ║ Birthday ║ The Park ║
║ Present 1 ║ Friend 1 ║ Birthday ║ The Park ║
║           ║ Friend 1 ║          ║ The Park ║
║           ║ Friend 1 ║ Birthday ║          ║
║           ║ Friend 1 ║ Birthday ║          ║
║           ║ Friend 1 ║ Birthday ║ The Park ║
║ Present 1 ║ Friend 1 ║          ║ The Park ║
║ Present 1 ║ Friend 1 ║ Birthday ║ The Park ║
╚═══════════╩══════════╩══════════╩══════════╝

I use the same data repeatedly on purpose to illustrate what I'm seeing. Even if a model's property renders correctly in some table cells, it won't in others, and seems to randomly but 100% consistently between page refreshes populate and not populate the same table cells. Which cells are populated and not are also different between User models in this example.

Hopefully this example makes sense, I know I could flatten data but in my actual app I can't and being able to include deeply nested relationships like this and have them show in templates correctly would be great.

It seems to mostly work, but fail for some reason that I imagine have to do with Promises. If I look in Ember inspector, all of the data is there, as evident by showing in most of the cells anyway.

What am I doing wrong and what can I do better if I want to take advantage of the { include: '' } feature of Ember Data's JSON API adapter?




Aucun commentaire:

Enregistrer un commentaire