防止$ scope变量副本听取其原始副本

时间:2015-02-20 21:19:26

标签: javascript angularjs angularjs-scope

在我的AngularJS应用程序中,我通常使用$rootScope传递数据。在各种状态下,我操纵在必要时将它们拉入$ scope。但由于$ scope具有原型继承,我认为这只是为了可读性而不是其他。在我的应用程序中,有以下变量......

$rootScope.list // object
$rootScope.list.items // array
$rootScope.additions // array
$rootScope.cart // object
$rootScope.cart.items // array

在开始之前,这通常以伪代码布局。所以,如果它不正确,那没关系。我正在寻找一个概念性的理解。

首先,购物车是空的。您查看list.items并将单个列表项复制到cart.items数组中。这很有效,直到我们开始讨论具有唯一additions的重复项目。

说,我想要有2个相同的项目,除了一个项目有不同的添加项目(购物车项目有数量属性,而不是列表项目)。

$rootScope.cart.items = [
   {
      name: 'listItem1',
      quantity: 3,
      additions: ['addition1']
   }, {
      name: 'listItem2',
      quantity: 1,
      additions: ['addition2']
   }, {
      name: 'listItem1', // same as cart.items[1], but additions has diff values
      quantity: 1,
      additions: ['addition1','addition2']
   }];

首先,AngularJS抱怨说因为我的ng-repeater中有重复项。我通过在track by $index指令中附加ng-repeat来解决该问题。这也是我看到的第一个红旗告诉我​​,我做错了什么。

我的第一个想法是创建一个临时cartItem,任意添加其添加内容,然后将其推送到$rootScope.cart.items[]。但是,当它将第3个购物车项目推到购物车上时,这是第一个列表项目的另一个副本,它会覆盖第一个购物车项目的additions[]。所以,$rootScope.cart.items看起来像这样:

$rootScope.cart.items = [
   {
      name: 'listItem1',
      quantity: 3,
      additions: ['addition1','addition2']
   }, {
      name: 'listItem2',
      quantity: 1,
      additions: ['addition2']
   }, {
      name: 'listItem1', // same as cart.items[1], but additions has diff values
      quantity: 1,
      additions: ['addition1','addition2']
   }];

从这个结果来看,当涉及将$ rootScope变量从一个地方复制到另一个地方时,它表面上是通过引用传递的。

所以,我的下一个想法是尝试使用带有隔离范围的指令。但我很快意识到我的逻辑是错误的。虽然隔离范围会给我单向数据绑定,但它并没有朝着我希望的方向发展。指令的作用域范围仍然可以设置值。

我理想的做法是随意将list.items添加到cart.items。但是来自同一个列表项的任何购物车项目,我希望彼此不受约束。因此,一个副本中的添加可能与另一个副本中的添加不同。 实现这一目标的最佳方法是什么?我觉得使用$rootScope在我的应用中的状态之间传递数据可能是一个糟糕的决定,尽管这是最快的方式我找到了。

2 个答案:

答案 0 :(得分:1)

您正在寻找Angular副本。

https://docs.angularjs.org/api/ng/function/angular.copy

您可以在文档中看到使用此方法的几种方法,但我的同事和我发现使用可选的“目标”选项可以更好地使用它。

这就是它的工作原理

首先设置新的目标数组。

var newArray = [];

然后将其用作角度复制中的目的地

angular.copy(firstArray, newArray);

你去,就这么简单!

现在您的新阵列将不再连接到原始阵列。

我还会考虑使用工厂作为代码的服务,而不是使用rootScope。学习可以提高您的工作效率,使您的代码更具可读性和用户友好性。这是一篇关于它的好文章。

http://tylermcginnis.com/angularjs-factory-vs-service-vs-provider/

修改

正如评论中提到的那样,这确实是一本很深的副本。这意味着它将复制数组中的所有子对象和数组。

答案 1 :(得分:0)

当您编辑第一个购物车项目的additions时,您实际上编辑了第一个和第三个购物车项目的additions,因为它们是相同的。

当您创建第三个购物车项目时,您可以复制第一个购物车项目的属性:

var newCartItem = {};

newCartItem.name = firstCartitem.name;
newCartItem.quantity = firstCartitem.quantity;
// Do not point to the other array, instead create a new one and copy over
newCartItem.additions = [];
for (var i = 0; i < firstCartitem.additions.length; i++) {
  newCartItem.additions.push( firstCartitem.additions[i] );
}
// Now you can add anything to the new cart item without editing the first one