如何使用EmberJS在路由中加载belongsTo / hasMany关系

时间:2014-08-19 11:10:54

标签: ember.js ember-data

在我的EmberJS应用程序中,我显示了一个约会列表。在AppointmentController中的一个动作中,我需要获得约会所有者,但是所有者总是返回" undefined"。

我的档案:

模型/ appointment.js

import DS from 'ember-data';

export default DS.Model.extend({
    appointmentStatus: DS.attr('number'),
    owner: DS.hasMany('person'),
    date: DS.attr('Date')
});

模型/ person.js

import DS from 'ember-data';

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

模板/ appointmentlist.js

{{#each appointment in controller}}
    <div>
        {{appointment.date}} <button type="button" {{action 'doIt'}}>Do something!</button>
    </div>
{{/each }}

控制器/ appointmentlist.js

export default Ember.ArrayController.extend({
    itemController: 'appointment'
});

控制器/ appointment.js

export default Ember.ObjectController.extend({
    actions:{
        doIt: function(){
            var appointment = this.get('model');
            var owner = appointment.get('owner'); //returns undefined
            //Do something with owner
        }
    }
});

现在,我知道我可以将owner-property更改为owner: DS.hasMany('person', {async: true}),然后处理从appointment.get('owner');返回的承诺,但这不是我想要的。 我发现如果我在约会列表模板中执行此{{appointment.owner}}或此{{appointment.owner.name}},则会从服务器获取所有者记录。所以我猜Ember不会加载关系,除非它们在模板中使用。

我认为我的问题的解决方案是使用预约列表路由来获取belongsTo关系中的记录。但我无法弄清楚如何。

也许是这样的?

路由/ appointmentlist.js

export default Ember.Route.extend({
    model: function() {
        return this.store.find('appointment');
    },
    afterModel: function(appointments){
        //what to do
    }
});

修改

我这样做了:

路由/ appointmentlist.js

export default Ember.Route.extend({
    model: function() {
        return this.store.find('appointment');
    },
    afterModel: function(appointments){
         $.each(appointments.content, function(i, appointment){

                var owner= appointment.get('owner')   
         });
    }
});

它有效,但我不喜欢这个解决方案...

3 个答案:

答案 0 :(得分:21)

您仍然异步加载这些记录,因此如果您足够快,您仍然可能未定义。最好从afterModel钩子返回一个promise,或者只是修改模型钩子来完成所有操作。

model: function() {
  return this.store.find('appointment').then(function(appointments){
    return Ember.RSVP.all(appointments.getEach('owner')).then(function(){
      return appointments;
    });
  });
}

model: function() {
  return this.store.find('appointment');
},
afterModel: function(model, transition){
  return Ember.RSVP.all(model.getEach('owner'));
}

答案 1 :(得分:3)

另一种方法是:

export default Ember.Controller.extend({
  modelChanged: function(){
    this.set('loadingRelations',true);
    Ember.RSVP.all(this.get('model').getEach('owner')).then(()=>{
      this.set('loadingRelations',false);
    });      
  }.observes('model')
});

这样,转换完成得更快,之后加载关系。可以通过loadingRelations观察加载状态。

当有很多关系要加载时,我认为这会提供更好的用户体验。

答案 2 :(得分:1)

您希望加载路线中的所有关联,因为您希望将Fastboot用于搜索引擎并更好地首次使用网站。

在加载主模型后保持关联加载可能不是最好的决定。

我使用语法加载路径中的所有关联:

   let store = this.store;
   let pagePromise = store.findRecord('page', params.page_id);
   let pageItemsPromise = pagePromise.then(function(page) {
     return page.get('pageItems');
   });
  return this.hashPromises({
    page: pagePromise,
    pageItems: pageItemsPromise
  });

对于this.hashPromises,我得到了一个混音:

    import Ember from 'ember';

    export default Ember.Mixin.create({
      hashPromises: function(hash) {
        let keys = Object.keys(hash);

        return Ember.RSVP.hashSettled(hash).then(function(vals) {
          let returnedHash = {};
          keys.forEach(function(key) {
            returnedHash[key] = vals[key].value;
          });
          return returnedHash;
        });
      }
    });