【问题标题】:Angular $watch with array splice带数组拼接的角度 $watch
【发布时间】:2017-12-04 15:05:59
【问题描述】:

我遇到了关于 Angular 和数组拼接中的观察者的问题。结合起来他们都有一个非常奇怪的行为。所以我创建了一个小演示,其中包含显示正在发生的问题的日志。这是我拥有的代码,或者您可以在 Plunker 中看到它的工作原理。

html:

<div class="logs">
    <div><b>LOGS:</b></div>
    <ul ng-repeat="watchEntry in watchersLogs track by $index">
      <li>{{watchEntry}}</li>
    </ul>
    <div><b>Watcher Count:</b> {{watchers.length}}</div>
</div>
<div class="item" ng-repeat="item in list" ng-init="InitItem()">
  <div class="item-title-wrapper">
    <span class="item-title">Item {{ $index + 1 }}</span>
    <button ng-click="AddNewItem()">Add New</button>
    <button ng-click="RemoveItem()">Remove</button>
  </div>
  <div class="field">
    <div>
      CREDIT:
      <input type="number" name="credit" ng-model="item.credit" />
    </div>
    <div>
      DEBIT:
      <input type="number" name="debit" ng-model="item.debit" />
    </div>
  </div>
</div>

js:

var app = angular.module("listApp", []);
app.controller("listController", function($scope) {
  // list with all data:
  $scope.list = [{
    credit: 2000,
    debit: 0
  }, {
    credit: 100000,
    debit: 1000
  }];

  // list containing all watchers:
  $scope.watchers = [];
  // logs containing all watcher event:
  $scope.watchersLogs = [];

  function SetWatcher(itemIndex) {
    $scope.watchers.splice(itemIndex, 0, $scope.$watch("list[" + itemIndex + "]", function(newValues, oldValues, scope) {
      $scope.watchersLogs.push("Item " + itemIndex + " watcher fired!");
    }, true));
  }

  $scope.InitItem = function() {
    // set a watcher for newly create item:
    SetWatcher(this.$index);
  }

  $scope.AddNewItem = function() {
    var newItem = {
      credit: 0,
      debit: 0
    };

    // put the item into the array:
    $scope.list.splice((this.$index + 1), 0, newItem);
  };

  $scope.RemoveItem = function() {
    // destroy the watcher:
    $scope.watchers[this.$index]();
    $scope.watchers.splice(this.$index, 1);
    // remove the item from the list:
    $scope.list.splice(this.$index, 1);
  };
});

css:

.logs {
  margin-bottom: 50px;
}

.item {
  margin-bottom: 25px;
}

因此,正如您在此处看到的,当我在 $scope.list 数组中初始化或添加新项目时,我正在为其分配一个新的观察者。从日志中您可以看到每个观察者在启动时只被触发一次,这很好。但是,我的应用程序需要在您选择或当前审查的项目之后添加该项目 /e.g.如果您有 3 个项目并单击第 2 个的 Add New 按钮,它应该在第 3 个位置/添加一个新条目。这就是我使用splice的原因。

但是,这会导致 $watch 表达式有时会被执行多次。因此,如果您在最后一个位置添加一个新条目,它只会为它触发一次 $watch 表达式。没关系。但是,如果你在中间的某个地方添加它 /e.g. 2nd, 3rd, etc./,观察者表达式不仅会被触发,还会触发它之后的所有其他项目。我猜splice 在新创建的项目之后会以某种方式更改项目的引用,这就是为什么在发生这种情况时会执行$watch

我需要$watch 表达式,因为当值被更改时我正在做一些计算,所以我认为我无法摆脱它们。正如我之前提到的,我也需要splice 功能......那么,有什么想法可以解决这个问题吗?

提前致谢! :)

...更新...

我解决了这个问题!非常感谢@Deblaton Jean-Philippe 的帮助。所以,首先我创建了一个删除观察者的新函数:

function RemoveWatcher(itemIndex) {
  if ($scope.watchers[itemIndex]) {
    // destroy the watcher:
    $scope.watchers[itemIndex]();
    // remove it from the array as well:
    $scope.watchers.splice(itemIndex, 1);
  }
}

我在设置新的观察者之前调用它,以确保它被清除。我也在 RemoveItem 方法中调用它,但这里棘手的是我总是从数组中删除最后一个观察者条目,因为我正在拼接 $scope.list 数组并且它改变了田野。所以我在那里做的只是像这样调用RemoveWatcher 方法:

RemoveWatcher($scope.watchers.length - 1);

这似乎工作得很好!您也可以检查更新的 Plunker。 :)

【问题讨论】:

  • 请在您的帖子中包含所有相关代码,并且不要仅包含链接。您的帖子应该独立于任何其他资源;考虑一下如果该站点将来出现故障会发生什么! (我们知道,这将是可怕的。)此外,有些人在禁止使用代码共享网站的公司防火墙后面。
  • 完成! :) 我用代码更新了我的问题并添加了解决方案。感谢您的评论。

标签: javascript angularjs arrays watch splice


【解决方案1】:

代码正在执行您要求他执行的操作。他在看你问的指数的价值。

如果你添加一个新的手表并且索引已经注册,它会被触发两次。

如果您查看文档here,您会看到$watch() 返回一个函数。执行此功能将注销您的手表。

您需要做的是,当您添加新项目时,取消注册那里的手表。

也许这样的事情可以帮助你:

  function SetWatcher(itemIndex) {
    if($scope.watchers[itemIndex]) $scope.watchers[itemIndex]();
    $scope.watchers.splice(itemIndex, 0, $scope.$watch("list[" + itemIndex + "]", function(newValues, oldValues, scope) {
      $scope.watchersLogs.push("Item " + itemIndex + " watcher fired!");
    }, true));
  }

【讨论】:

  • 你完全正确!在设置观察者时应用这个简单的检查来解决问题。非常感谢你的帮助! :))
  • 我认为这段代码还不够。如果您在数组中间添加一些东西,我很确定您的数组的最后一项不会触发单个手表。我建议您始终在数组末尾添加项目,并使用过滤器 (|) 对视图进行排序。
  • 实际上,我所做的是使用splice 添加新项目,但是当我从按钮中删除它们时,我总是从数组中删除最后一个观察者。我似乎锻炼得很完美。检查更新的 Plunker :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-24
  • 2020-10-15
  • 2016-10-19
  • 2019-04-17
  • 1970-01-01
  • 1970-01-01
  • 2020-05-11
相关资源
最近更新 更多