阻止$scope变量副本侦听其原始副本

Prevent $scope variable copy from listening to its original

本文关键字:副本 原始 阻止 scope 变量      更新时间:2024-02-26

在我的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的重复项。

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

$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中继器中有重复项。我通过在ng-repeat指令中添加track by $index解决了这个问题。这也是我看到的第一个告诉我我做错了什么的红旗。

我的第一个想法是创建一个临时cartItem,任意添加它的附加内容,然后将它推送到$rootScope.cart.items[]上。但是,当将第三个购物车项目推到购物车上时,它会覆盖第一个购物车的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。但任何来自同一列表项的cart项,我都希望彼此解除绑定。因此,一个副本中的添加可能与另一个副本的添加不同实现这一目标的最佳方式是什么我有一种感觉,使用$rootScope在我的应用程序中的状态之间传递数据可能是一个糟糕的决定,尽管这是我找到的最快的方法。

您正在寻找的是角度副本。

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

有几种方法可以使用,你会在文档中看到,但我和我的同事发现使用可选的"destination"选项更好。

就是这样工作的

首先设置你的新目标阵列。

var newArray = [];

然后你用它作为角度复制的目的地

angular.copy(firstArray, newArray);

好了,就这么简单!

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

我也会考虑使用工厂作为代码的服务,而不是使用rootScope。学习这一点将大大提高您的生产力,并使您的代码更加可读和用户友好。这是一篇关于它的好文章。

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

编辑

正如有人在评论中提到的那样,这确实是一个深度复制。这意味着它将复制数组内部的所有子对象和数组。

当您编辑第一个购物车项目的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