【问题标题】:Prevent $scope variable copy from listening to its original防止 $scope 变量副本监听其原始
【发布时间】:2015-02-21 05:49:04
【问题描述】:

在我的 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 中有重复项。我通过在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。但是任何来自同一个列表项的购物车项目,我都希望彼此不绑定。因此,一个副本中的添加可能与另一副本中的添加不同。 实现这一目标的最佳方式是什么?我觉得使用 $rootScope 在我的应用程序中的状态之间传递数据可能是一个糟糕的决定,尽管这是我拥有的最快的方式找到了。

【问题讨论】:

  • docs.angularjs.org/api/ng/function/angular.copy -- 这将帮助您制作数组的副本。另外,是的,您应该尽量不使用 rootScope,总有另一种方法。在您的情况下,您可以使用工厂
  • 太好了,我想这会使$rootScope.cart.items 成为$rootScope.list.items 的浅拷贝。如果您想对此做出回答,我将不胜感激!越详细越好。
  • 对,只是指我之前的实现。

标签: javascript angularjs angularjs-scope


【解决方案1】:

Angular 副本正是您要寻找的。​​p>

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/

编辑

而且正如 cmets 中有人提到的,它确实是一个深拷贝。这意味着它将复制数组内的所有子对象和数组。

【讨论】:

  • 工作就像一个魅力!非常感谢。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-09
    • 1970-01-01
    • 1970-01-01
    • 2012-06-28
    • 2013-01-05
    • 1970-01-01
    相关资源
    最近更新 更多