7

我在我的应用程序中使用了一个 ArrayController,它是通过应用程序的路由器从 Ember Data REST 调用提供的:

postsController.connectOutlet('comment', App.Comment.find({post_id: post_id}));

对于 Post UI,我可以添加/删除评论。当我这样做时,我希望能够通过删除或添加相同的元素来更新 postsController 的 contentArray 以向用户提供视觉反馈,但 Ember Data 并不好玩:

Uncaught Error: The result of a server query (on App.Comment) is immutable.

根据下面sly7_7的评论,我刚刚注意到没有查询(App.Comment.find())时结果确实是DS.RecordArray,但是在有查询的情况下(App.Comment.find({post_id: post_id}),返回一个 DS.AdapterPopulatedRecordArray。

我是否必须 .observes('contentArray') 并创建一个可变副本?或者有没有更好的方法来做到这一点?

4

4 回答 4

7

这是我最终实施以解决此问题的方法。正如问题中提出的那样,我知道的唯一解决方案是创建我通过添加和删除维护的内容的可变副本:

contentChanged: function() {
    var mutableComments = [];

    this.get('content').forEach(function(comment) {
        mutableComments.pushObject(comment);
    });

    this.set('currentComments', mutableComments);
}.observes('content', 'content.isLoaded'),

addComment: function(comment) {
    var i;
    var currentComments = this.get('currentComments');
    for (i = 0; i < this.get('currentComments.length'); i++) {
        if (currentComments[i].get('date') < comment.get('date')) {
            this.get('currentComments').insertAt(i, comment);
            return;
        }
    }

    // fell through --> add it to the end.
    this.get('currentComments').pushObject(comment);
},

removeComment: function(comment) {
    this.get('currentComments').forEach(function(item, i, currentComments) {
        if (item.get('id') == comment.get('id')) {
            currentComments.removeAt(i, 1);
        }
    });
}

然后在模板中,绑定到 this 计算属性:

{{#each comment in currentComments}}
    ...
{{/each}}

我对这个解决方案不满意——如果有更好的方法,我很想听听。

于 2012-08-13T16:35:23.513 回答
2

评论会太长...

我不知道您如何尝试添加记录,但您可以尝试这样做:App.Comment.createRecord({})。如果一切顺利,它将自动更新您的控制器内容。(我认为 App.Comment.find() 的结果是一个“实时”数组,创建记录时会自动更新)以下是我们在应用程序中执行此操作的方法:

App.ProjectsRoute = Ember.Route.extend({
  route: 'projects',

  collection: Ember.Route.extend({
    route: '/',

    connectOutlets: function (router) {
      router.get('applicationController').connectOutlet({
        name: 'projects',
        context: App.Project.find()
      });
    }
 })

然后,创建项目的处理程序(在路由器中):

createProject: function (router) {
  App.Project.createRecord({
    name: 'new project name'.loc()
  });
  router.get('store').commit();
},
于 2012-08-10T19:16:43.103 回答
0

仅作记录:截至今天(使用 Ember Data 1.0.0-beta),该库已将这种情况考虑在内。当数组中的记录被删除时,数组将被更新。

如果您尝试手动删除该数组上的元素,例如在包含控制器的模型(它是一个 ArrayController,因此它的模型是一个记录数组)上使用 .removeObject(object_you_just_deleted),您将收到类似的错误:

“服务器查询的结果(在 XXXXX - 您尝试手动更新的模型)是不可变的”。

所以不再需要手动编码从它所属的数组中删除记录。这是个好消息,因为我一直喜欢使用 ED 并一直在使用它...... :)

于 2014-11-17T16:28:30.700 回答
0

前言

我有一个类似的问题,并找到了一个有点棘手的解决方案。运行 Ember-Data 源代码和 API 文档为我清除了 AdapterPopulatedRecordArray 从查询的查找请求返回的事实。手册上是这么说的:

AdapterPopulatedRecordArray 表示记录的有序列表,其顺序和成员资格由适配器确定。例如,发送到适配器的查询可能会触发服务器上的搜索,其结果将加载到 AdapterPopulatedRecordArray 的实例中。

所以不变性的一个很好的理由是这些数据是由服务器控制的。但如果我不需要它怎么办?例如,我有一个包含许多任务的任务列表模型,我在任务列表控制器中以类似的方式找到它们

this.get('store').find('task',{tasklist_id: this.get('model').get('id')})

而且我还有一个大红色按钮“添加任务”,它必须创建并保存新记录,但我不想向服务器发出新的查找请求以重绘我的模板并显示新任务。对我来说,好的做法是

var task = this.store.createRecord('task', {
    id: Utils.generateGUID(),
    name: 'Lorem ipsum'
});
this.get('tasks').pushObject(task);

在那种情况下,我得到了宣布的错误。但是,嘿,我想酒后驾车!

解决方案

DS.AdapterPopulatedRecordArray.reopen({
    replace: DS.RecordArray.replace
})

就是这样了。一点“我自己”的余烬灵活性黑客。

于 2015-03-14T18:01:35.567 回答