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

时间:2014-09-12 10:02:13

标签: ember.js

我使用ember.js和localstorage-adapter

这是一个带有问题的JSbin:http://jsbin.com/lejizo/9/edit?html,console,output

拥有这些模型:

/* 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})使应用程序顺利运行。

问题在于,如果我尝试从Controller访问items它们不是对象,它们只是一个承诺!这迫使我们使用以下方法:

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

这对我来说似乎很尴尬,要始终注意hasMany关系并小心你如何使用它们,而不是仅仅使用相关对象来处理任何其他关系..

这是正常还是我错过了什么? 有没有解决方法来不定义它们async:true,因为所有数据都已经在localstorage中了? 我们是否应始终将控制器用于所有相关实体作为最佳实践?

1 个答案:

答案 0 :(得分:2)

  

这对我来说似乎很尴尬,要始终注意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. The RSVP Promise library
  2. Ember's guide on asynchrony
  3. ObjectProxyArrayProxy
  4. PromiseProxyMixin班级
  5. 编辑:如果你想修改关系,例如,添加一个新项目,做这样的事情:

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