对象 属性 的值未在 Ember 的本地存储中更改

The value of object's property is not being changed in the Local Storage in Ember

我正在 Ember 中建立一个商店,当用户点击 添加到购物车 按钮。每个产品都是一个对象,它有一个名为 ordered_quantity 的 属性,当用户试图从购物车中删除产品时,我试图更改此 属性 的值。 (例如:ordered quantity: 8,单击按钮时应为 7)。

我的服务文件中有以下代码:

remove(item) {
  let new_arr = this.get('items');
  let elementIndex = new_arr.findIndex(obj => {
    return obj.id === item.id;
  });

  if (elementIndex !== -1) {
    new_arr[elementIndex].ordered_quantity = new_arr[elementIndex].ordered_quantity - 1;
  } 
  this.set('cart.items', new_arr);
}

我正在使用本地存储插件 (https://github.com/funkensturm/ember-local-storage#methods)

我有以下操作:

actions: {
  removeFromCart(){
    this.get('cart').remove(this.product);
  }
}

当我尝试 运行 以下代码时出现错误:

Uncaught Error: Assertion Failed: You attempted to update [object Object].ordered_quantity to "7", but it is being tracked by a tracking context, such as a template, computed property, or observer. In order to make sure the context updates properly, you must invalidate the property when updating it. You can mark the property as @tracked, or use @ember/object#set to do this.

我试过像这样使用设置函数:

let updated = item.ordered_quantity - 1;
set(item, 'ordered_quantity', updated);

https://api.emberjs.com/ember/release/functions/@ember%2Fobject/set 并且代码按预期工作没有错误,但是我的 属性 ordered_quantity 的值没有在本地存储中更新。

您需要根据您的用例调整 set 函数:

remove(item) {
  let new_arr = this.get('items');
  let elementIndex = new_arr.findIndex(obj => {
    return obj.id === item.id;
  });

  if (elementIndex !== -1) {
    set(new_arr[elementIndex], 'ordered_quantity', new_arr[elementIndex].ordered_quantity - 1);
  } 
  this.set('cart.items', new_arr);
}

基于@Lux 的原始答案(以及针对 Ember 3.16+ 时代的更新),我想补充一点,您可以使用函数式编程模式来稍微清理一下:

如果在您的 cart 服务中,项目是 @tracked,像这样:

import Service from '@ember/service';
import { tracked } from '@glimmer/tracking';

export default class CartService extends Service {
  @tracked items = [];
}

注意:假设 ordered_quantity 被跟踪。

remove(item) {
  for (let obj of this.items) {
    if (item.id !== obj.id) continue;

    // set must be used because quantity is not known to the tracking system
    set(obj, 'ordered_quantity', obj.ordered_quantity - 1);
  });

  // invalidate the reference on the card service so that all things that
  // reference cart.items re-compute
  this.cart.items = this.items;
}

这是一个现场演示:https://ember-twiddle.com/e18433b851091b527512e27ae792640c?openFiles=components.demo%5C.js%2C

还有一个实用插件,它允许与数组、对象等进行更符合人体工程学的交互:https://github.com/pzuraq/tracked-built-ins

上面的代码看起来像这样:

import Service from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { TrackedArray } from 'tracked-built-ins';

export default class CartService extends Service {
  @tracked items = new TrackedArray([]);
}

然后在你的组件中:

remove(item) {
  for (let obj of this.items) {
    if (item.id !== obj.id) continue;

    // set must be used because quantity is not known to the tracking system
    set(obj, 'ordered_quantity', obj.ordered_quantity - 1);
  });
}

这是一个现场演示:https://ember-twiddle.com/23c5a7efdb605d7b5fa9cd9da61c1294?openFiles=services.cart%5C.js%2C

然后您可以更进一步,为您的“项目”添加跟踪。

那么您的删除方法将如下所示:

remove(item) {
  for (let obj of this.items) {
    if (item.id !== obj.id) continue;

    obj.ordered_quantity = obj.ordered_quantity - 1;
  });
}

这是一个现场演示:https://ember-twiddle.com/48c26e2e0f0e5f3ac7685e4bdc0eda4e?openFiles=components.demo%5C.js%2C