Javascript 带阵列拼接的角形手表

Javascript 带阵列拼接的角形手表,javascript,angularjs,arrays,watch,splice,Javascript,Angularjs,Arrays,Watch,Splice,我在角度和阵列拼接中遇到了一个关于观察者的问题。他们两人的行为都很奇怪。因此,我创建了一个小演示,日志显示了正在发生的问题。这是我的代码,或者你可以看到它在这里工作 html: <div class="logs"> <div><b>LOGS:</b></div> <ul ng-repeat="watchEntry in watchersLogs track by $index"> <li&g

我在角度和阵列拼接中遇到了一个关于观察者的问题。他们两人的行为都很奇怪。因此,我创建了一个小演示,日志显示了正在发生的问题。这是我的代码,或者你可以看到它在这里工作

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>
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);
  };
});
.logs {
  margin-bottom: 50px;
}

.item {
  margin-bottom: 25px;
}
css:

<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>
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);
  };
});
.logs {
  margin-bottom: 50px;
}

.item {
  margin-bottom: 25px;
}
因此,如您所见,当我在
$scope.list
数组中初始化或添加一个新项时,我会为它分配一个新的观察程序。从日志中可以看出,每个观察者在启动时只被触发一次,这很好。但是,我的应用程序需要在您选择的项目或当前正在审阅的项目之后添加该项目/。这就是为什么我要使用
splice

但是,这有时会导致执行多次
$watch
表达式。因此,如果在最后一个位置添加一个新条目,它将只为它触发一次
$watch
表达式。没关系。但是,如果你把它添加到中间(例如第二,第三,等等),观察者的表达式不仅会对它进行激发,而且会对它后面的所有其他项目进行激发。我猜
splice
会在新创建的项目之后以某种方式更改项目的引用,这就是为什么发生这种情况时会执行
$watch

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

提前感谢!:)

…更新…

我解决了这个问题!非常感谢@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);
  }
}
在设置新的观察者之前,我会打电话给它,以确保它被清除。我我也在
removietem
方法中调用它,但这里的棘手问题是,我总是从数组中删除最后一个观察者条目,因为我正在拼接
$scope.list
数组,它会更改字段的顺序。因此,我在这里所做的只是调用
RemoveWatcher
方法,如下所示:

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

这似乎是完美的工作!您还可以检查更新的Plunker:)

代码正在执行您要求他执行的操作。他正在观察你所要求的指数的价值

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

如果查看文档,您将看到
$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:)请在帖子中包含所有相关代码,不要只包含链接。你的帖子应该独立于任何其他资源;考虑一下如果网站将来发生了什么会发生什么!(我们知道,这会很糟糕。)此外,一些人在禁止使用代码共享网站的公司防火墙后面。完成!:)我用代码更新了我的问题,并添加了解决方案。谢谢你的评论。