EmberJS - hasMany Fixtures模型空值

时间:2022-09-09 21:11:11

I have 3 different fixture models, as shown below.

我有3种不同的夹具型号,如下图所示。

var Room = DS.Model.extend({
       title: DS.attr('string'),
       categories: DS.hasMany('Category', { async: true }),
       isSelected: DS.attr('boolean')
});
var Category = DS.Model.extend({
    title: DS.attr('string'),
    room: DS.belongsTo('Room', {async: true }),
    materials: DS.hasMany('Material', { async: true }),
    isSelected: DS.attr('boolean')
});
var Material = DS.Model.extend({
    title: DS.attr('string'),
    category: DS.belongsTo('Category', {async: true} ),
    isSelected: DS.attr('boolean')
});

I find when I try to view the contents inside the Materials model it is blank. In my controller I expose the materials by doing this:

我发现当我尝试查看Materials模型中的内容时,它是空白的。在我的控制器中,我通过这样做来暴露材料:

currentMaterials: function() {
  var room = this.filterBy('isSelected', true).get('firstObject');
  var categories = room.get('categories');
  var selectedCategory = categories.get('firstObject');
  var material = selectedCategory.get('materials');
  return material;

}.property('@each.isSelected')

However when I try to access currentMaterials the value is null. I am ONLY able to access its values if I first access the Rooms/Categories using a {{#each} loop. Oddly once I do the {{#each}} I am then able to access the values in currentMaterials.

但是,当我尝试访问currentMaterials时,该值为null。如果我首先使用{{#each}循环访问Rooms / Categories,我只能访问其值。奇怪的是,一旦我执行{{#each}},我就可以访问currentMaterials中的值。

Does anyone understand why?

有谁理解为什么?

1 个解决方案

#1


1  

It's due to fact of promises existance. Your categories relationship is async, which means that it's not present initially and ember-data should fetch it if needed. However, it takes time to fetch data, therefore ember-data returns a promise from this: var categories = room.get('categories'). After that promise, you first get firstObject from it, which does not exist for a promise (is null), and than you get materials relationship from that null. It simply is null.

这是因为存在承诺的事实。您的类别关系是异步的,这意味着它最初不存在,并且如果需要,ember-data应该获取它。但是,获取数据需要时间,因此ember-data会从此返回一个承诺:var categories = room.get('categories')。在那个承诺之后,你首先从它获得firstObject,这对于promise是不存在的(为null),而不是从那个null获得材料关系。它只是空。

However, ember templates are smart and if you put an each on them, they know that these relationships are needed and makes ember-data fetch these data.

但是,ember模板很聪明,如果你把它们放在它们上面,它们就知道需要这些关系并使ember-data获取这些数据。

What you can do? If you need this data to perform page-specific job, you should make sure that you have access to it before showing the page to the user - therefore in the model hook. You can use Ember.RSVP to make multiple fetch calls and set them up in the controller:

你可以做什么?如果您需要此数据来执行特定于页面的作业,则应在向用户显示页面之前确保您可以访问它 - 因此在模型挂钩中。您可以使用Ember.RSVP进行多次提取调用并在控制器中进行设置:

model: function() {
  data =
    room: store.find("room")
    categories: store.find("category)
    materials: store.find("material")

  return Ember.RSVP.hash(data)
}

However, take notice that it will fetch all the materials, etc. If you need only the ones connected to your model, you should consider speeding up your data fetching using side loading. If you are using fixtures, it won't work.

但是,请注意它将获取所有材料等。如果只需要连接到模型的材料,则应考虑使用侧面加载来加速数据获取。如果您使用灯具,它将无法正常工作。

Last that I can think of is making computed property a method that would fetch the data, but set them on other variable. You can use some kind of flag to inform the app when the data is ready:

最后我能想到的是使计算属性成为一个获取数据的方法,但是将它们设置在其他变量上。您可以使用某种标志在数据准备就绪时通知应用:

currentMaterials: function() {
  var room = this.filterBy('isSelected', true).get('firstObject');
  room.get('categories').then(function(categories) {
    return categories.get('firstObject').get('materials');
  }).then(function(materials) {
    // here you have your materials
    // you can pass _this to that method and set these materials
    // on some kind of controller property (e.g. materialsChosen)
    // and use a flag like setting 'is Fetching' on the start of this
    // computed property and setting down right here
  });
}.property('@each.isSelected')

#1


1  

It's due to fact of promises existance. Your categories relationship is async, which means that it's not present initially and ember-data should fetch it if needed. However, it takes time to fetch data, therefore ember-data returns a promise from this: var categories = room.get('categories'). After that promise, you first get firstObject from it, which does not exist for a promise (is null), and than you get materials relationship from that null. It simply is null.

这是因为存在承诺的事实。您的类别关系是异步的,这意味着它最初不存在,并且如果需要,ember-data应该获取它。但是,获取数据需要时间,因此ember-data会从此返回一个承诺:var categories = room.get('categories')。在那个承诺之后,你首先从它获得firstObject,这对于promise是不存在的(为null),而不是从那个null获得材料关系。它只是空。

However, ember templates are smart and if you put an each on them, they know that these relationships are needed and makes ember-data fetch these data.

但是,ember模板很聪明,如果你把它们放在它们上面,它们就知道需要这些关系并使ember-data获取这些数据。

What you can do? If you need this data to perform page-specific job, you should make sure that you have access to it before showing the page to the user - therefore in the model hook. You can use Ember.RSVP to make multiple fetch calls and set them up in the controller:

你可以做什么?如果您需要此数据来执行特定于页面的作业,则应在向用户显示页面之前确保您可以访问它 - 因此在模型挂钩中。您可以使用Ember.RSVP进行多次提取调用并在控制器中进行设置:

model: function() {
  data =
    room: store.find("room")
    categories: store.find("category)
    materials: store.find("material")

  return Ember.RSVP.hash(data)
}

However, take notice that it will fetch all the materials, etc. If you need only the ones connected to your model, you should consider speeding up your data fetching using side loading. If you are using fixtures, it won't work.

但是,请注意它将获取所有材料等。如果只需要连接到模型的材料,则应考虑使用侧面加载来加速数据获取。如果您使用灯具,它将无法正常工作。

Last that I can think of is making computed property a method that would fetch the data, but set them on other variable. You can use some kind of flag to inform the app when the data is ready:

最后我能想到的是使计算属性成为一个获取数据的方法,但是将它们设置在其他变量上。您可以使用某种标志在数据准备就绪时通知应用:

currentMaterials: function() {
  var room = this.filterBy('isSelected', true).get('firstObject');
  room.get('categories').then(function(categories) {
    return categories.get('firstObject').get('materials');
  }).then(function(materials) {
    // here you have your materials
    // you can pass _this to that method and set these materials
    // on some kind of controller property (e.g. materialsChosen)
    // and use a flag like setting 'is Fetching' on the start of this
    // computed property and setting down right here
  });
}.property('@each.isSelected')