Ember本地存储如何在控制器中使用hasMany和async:true



我正在使用带有本地存储适配器的ember.js

以下是一个带有此问题的JSbin:http://jsbin.com/lejizo/9/edit?html,控制台,输出

拥有以下型号:

/* Models */
App.List = DS.Model.extend({
    name: DS.attr('string'),
    // DOES NOT WORK:: items: DS.hasMany('item')
    items: DS.hasMany('item', {async: true})
});  
App.Item = DS.Model.extend({
    name: DS.attr('string'),
    list: DS.belongsTo('list')
    });

如果不使hasMany异步,Ember数据将抛出错误。顺便说一下,数据在localstoarge中。我这样初始化它:

var FIXTURES = {
    'list': {
        records: {
            '1': { 
                id: '1', 
                name: 'The List', 
                items: ['1','2'] 
            },
            '2': { 
                id: '2', 
                name: 'The Second List', 
                items: ['1','3'] 
            }
        }
    },
    'item': {
        records: {
            '1': { 
                id: '1', 
                name: 'item 1', 
                list: '1' },
            '2': { 
                id: '2', 
                name: 'item 2', 
                list: '1' 
            },
            '3': { 
                id: '3', 
                name: 'item 3', 
                list: '1' 
            }
        }
    }
}
localStorage.setItem('DS.LSAdapter', JSON.stringify(FIXTURES));

无论如何,使items: DS.hasMany('item', {async: true})可以使应用程序顺利运行。

问题是,如果我试图从控制器访问items,它们不是一个对象,它们只是一个承诺!这迫使我们使用以下方法:

list.get('items').then(function(items) { // must use then
    items.forEach(function(item){
        console.log(item.get('id'));
    });
});  

这对我来说似乎很尴尬,总是要注意hasMany关系,并小心如何使用它们,而不是像处理任何其他关系那样只处理相关对象。。

这是正常的还是我错过了什么?有没有一种变通方法可以不将它们定义为async:true,因为所有数据都已经在本地存储中了?我们是否应该始终使用所有相关实体的then-in控制器作为最佳实践?

这对我来说似乎很尴尬,总是要注意hasMany关系,并小心如何使用它们,而不是像处理任何其他关系那样只处理相关对象。。

那会很尴尬,这就是为什么你不必这么做的原因。)在大多数情况下,Ember会自动监视属性更新并相应地传播它们。这是什么意思?这意味着你不应该担心价值是一个承诺使用它,就好像它不是一个

简言之,Ember使用了一种特殊的承诺来关注房产更新。假设您有以下模板:

{{#each item in model.items}}
    {{item.name}}
{{/each}}

如果model.items是一个异步的hasMany关系,Ember仍然会做正确的事情。当模板第一次渲染时,将没有数据您的each循环不会产生任何结果但是Ember会关注model.items属性的更新。当它有更新时(比如当promise解析时),Ember将再次运行模板。这一次,数据将在那里,它将完全按照您的期望工作。

属性也是如此:

function() {
    return this.get('model.items').filter(function(item) {
        return !!item;
    });
}.property('model.items.@each')

此属性在第一次运行时将返回一个空数组。但是,当承诺得到解决时,Ember将再次运行该属性并生成您想要的结果。

在这背后有很多事情要做,但在进入一些更复杂的用例之前,您通常不需要担心。如果你想了解更多,我建议你查看这些资源:

  1. RSVP Promise库
  2. Ember异步指南
  3. ObjectProxy和ArrayProxy类
  4. PromiseProxy Mixin类

编辑:如果你想修改关系,例如,添加一个新项目,可以这样做:

actions: {
    addPost: function(post) {
        this.get('model.posts').then(function(posts) {
            posts.addObject(post);
        });
    }
}

最新更新