【发布时间】:2012-04-20 07:19:48
【问题描述】:
我有以下型号:
App.Checklist = DS.Model.extend({
name: DS.attr('string'),
checkitems: DS.hasMany('App.Checkitem', { embedded: true }),
remainingItemsCount: function() {
var checkitemsToCount = this.get('checkitems');
return checkitemsToCount.filterProperty('isDone', false).get('length');
}.property()
});
我想显示一个清单列表,其中包含每个列表中当前未打开的检查项的计数。
如果我将以下内容放入模板中,我会得到正确的输出:
{{#each checklists}}
{{this.name}}
{{this.remainingItemsCount}}
{{/each}}
但是,如果将新的检查项添加到检查表中,则计数不会增加。
但是,如果我更改 Checklist 模型中的 remainingItemsCount 计算属性,使其依赖于 checkitems.@each.done,那么计数会随着新检查项的添加而增加。
问题在于,一旦添加此依赖项,子检查项的集合就会出错 - 它会不断重复第一个检查项的总检查项数(即,如果有五个项目的 'isDone' 为假,和四个 'isDone' 为真,则列表计数将显示为 9,第一个检查项将重复 9 次)。
我做错了什么?
更新:
事实证明,将依赖项添加到 remainingItemsCount 属性会导致 ember-data 对服务器进行新的调用。
在没有依赖的情况下,页面加载时会发出以下 XHR 请求:
GET http://localhost:3000/checklists
通过依赖,页面加载时会发出以下 XHR 请求:
GET http://localhost:3000/checklists
GET http://localhost:3000/checkitems
最后一个请求带有以下参数,这似乎是第一个检查项的表示,包装在“ids”哈希中:
{"ids"=>
{"0"=>
{"id"=>"182",
"checklist_id"=>"4",
"title"=>
"Make sure list count automatically increments",
"is_done"=>"false"}},
"action"=>"index",
"controller"=>"checkitems"}
我想知道这是不是因为checkitem 模型是用belongsTo 属性定义的?
App.Checkitem = DS.Model.extend({
title: DS.attr('string'),
isDone: DS.attr('boolean'),
checklist: DS.belongsTo('App.Checklist')
});
更新 2
我仍然不确定为什么,但很明显,将依赖项添加到属性中如下...
remainingItemsCount: function() {
var checkitemsToCount = this.get('checkitems');
return checkitemsToCount.filterProperty('isDone', false).length;
}.property('checkitems.@each.isDone').cacheable()
...导致 ember-data 的内置 DS.RESTAdapter 调用 findMany。 findMany 请求应该接受一个 id 数组,而是将一个包含一个完整检查项对象的数组传递给它,该数组嵌套在一个散列中,键为 0。
解决方案
最后,我将问题追溯到 ember-data 深处的以下观察者:
dataDidChange: Ember.observer(function() {
var associations = get(this.constructor, 'associationsByName'),
data = get(this, 'data'), store = get(this, 'store'),
idToClientId = store.idToClientId,
cachedValue;
associations.forEach(function(name, association) {
if (association.kind === 'hasMany') {
cachedValue = this.cacheFor(name);
if (cachedValue) {
var ids = data.get(name) || [];
var clientIds = Ember.ArrayUtils.map(ids, function(id) {
return store.clientIdForId(association.type, id);
});
set(cachedValue, 'content', Ember.A(clientIds));
cachedValue.fetch();
}
}
}, this);
}, 'data')
当观察者到达return store.clientIdForId(association.type, id) 行时,数组ids 是一个检查项对象数组,而不是一个id 整数数组。修复非常简单:return store.clientIdForId(association.type, id.id) 返回一个 id 整数数组。
【问题讨论】:
标签: javascript ember.js