`DS.attr()` 中的嵌套对象不受 `DS.rollbackAttributes()` 的影响

Nested object in `DS.attr()` isn't affected by `DS.rollbackAttributes()`

我有一个模型 User 如下:

import DS from 'ember-data';

const { attr, Model } = DS;

export default Model.extend({
  name: attr("string"),
  properties: attr(),
});

User.properties 旨在容纳一个 JSON 对象。

我正在通过如下形式(使用 ember-one-way-controls)更新模型:

{{one-way-textarea
  model.name
  update=(action (mut model.name))}}

{{one-way-textarea
  model.properties.description
  update=(action (mut model.properties.description))}}

我有一个按钮,允许用户通过调用 discardChanges 操作来放弃更改:

actions: {
  discardChanges(model) {
    model.rollbackAttributes();
  },
},

name 属性更改被正确丢弃/重置,但 properties 属性不是。

我该如何处理?

问题的来源

Ember 数据不知道更改,因为它使用 === 运算符将脏属性与原始属性进行比较。如果发现更改,Ember Data 会将脏属性键存储在 _attributes 数组中。 We notice this here. Then, when you call DS.rollbackAttributes(), the model looks at the _attributes to acknowledge the attributes to restore. Here it is.

但是哈希值不一样!

JS 是关于通过引用传递值的。这是来自 Node 解释器的示例:

> var foo = { description: 'hello' }
undefined
> var bar = foo;
undefined
> bar.description = 'bonjour';
'bonjour'
> bar === foo
true

您正在修改原始对象。

解决方案

一个可能的解决方案是深度复制您的 properties 对象并在调用 discardChanges.

时手动重置它

您可以将其实现为服务:

import Ember from 'ember';

const { copy, Service } = Ember;

export default Service.extend({
  savedProperties: null,

  finalize() {
    this.set('savedProperties', null);
  },

  start(model) {
    const properties = copy(model.get('properties'));
    this.set("savedProperties", properties);
  },

  undo(model) {
    const savedProperties = this.get('savedProperties');
    for (const property in savedProperties) {
      if (savedProperties.hasOwnProperty(property)) {
        const keyPath = `properties.${property}`;
        model.set(keyPath, savedProperties[property]);
      }
    }
    this.set('savedProperties', null);
  },
});
  • 进入编辑模式时调用start
  • 当您想放弃更改时调用 undo
  • 当您成功保存您的记录时,您调用finalize