【问题标题】:ngRepeat track by: How to add event hook on model change?ngRepeat track by:如何在模型更改时添加事件挂钩?
【发布时间】:2015-06-04 17:49:57
【问题描述】:

我有一个简单的 ngRepeat,如下所示:

<some-element ng-repeat="singleRecord in arrayOfRecords track by singleRecord.id">
    <!-- stuff -->
</some-element>

arrayOfRecords 是从服务器更新的,可能包含新数据。

ngRepeattrack by 功能可以判断何时将新元素添加到数组中并自动更新 DOM 而无需更改现有元素。当有新数据进入或旧数据被删除时,我想挂钩该代码并执行回调函数。是否可以通过 Angular 轻松做到这一点?

据我了解,有一个$$watchers 会在某些变量发生更改时触发回调,但我不知道如何破解它。这是正确的方向吗?


注意:我知道我可以手动保存arrayOfRecords,并在我获取它们时将其与新值进行比较以查看发生了什么变化。但是,由于 Angular 已经提供了具有此逻辑的 track by 功能,如果我可以让 Angular 在从数组中添加或删除元素时自动触发事件回调,那就太好了。复制 Angular 中已经存在的这种逻辑是没有意义的。

【问题讨论】:

  • 很难检查对象是否发生了变化?
  • 你的意思是$scope.$watchCollection(..)track by 什么都想不通。
  • @Claies 我认为你误解了(或我)。据我了解,该问题与您提到的所有内容无关:)。为了简化 OP 想知道 array1 - array2 之间的差异可能是为了一些逻辑......所以 OP 所说的角度是在track by 逻辑中计算出来的,所以我可以使用类似内置的东西,它给了我没有我的 2 个列表之间的差异必须编写任何代码。
  • @Claies 这是我相信的 OP 思想的方法,或者换句话说 he wants to know when angular detects the change and updates the DOM --> 当 angular 在 刷新整个列表时发现何时删除/添加项目时 它是否可以通知我,以便我知道哪些所有项目都是唯一的,并且我可以在该唯一项目列表上做一些事情(我可以​​避免编写 Diffing 逻辑)。无论如何,这就是我解释它的方式。 OP应该能够澄清。
  • 我想你现在明白我的问题了——我对ngRepeattrack by 如何跟踪模型的有效更改很感兴趣(类比:电工如何拔出干墙) .您提供的链接讨论了 Angular 如何跟踪更改,但没有讨论它如何知道集合中哪些元素有效地更改了。我相信我已经对 Angular 的那一部分有足够的了解,知道这不是我想要的。无论如何,谢谢你试图理解。我意识到这可能不是一个常见问题,因为大多数人只是不关心优化。

标签: javascript angularjs angularjs-ng-repeat ng-repeat angularjs-track-by


【解决方案1】:

您可能可以创建一个指令并将其与 ng-repeat 一起添加,因此该指令在创建时(当项目由 ng-repeat 添加时)会发出一个事件,同样,当项目被销毁时它会发出另一个事件。

这里是一个简单的实现:

.directive('tracker', function(){
  return{
    restrict:'A',
    link:function(scope, el, attr){
      scope.$emit('ITEM_ADDED', scope.$eval(attr.tracker))
      scope.$on('$destroy', function(){
        scope.$emit('ITEM_REMOVED', scope.$eval(attr.tracker))
      });
    }
  }
});

并将其用作:

<some-element 
       ng-repeat="singleRecord in arrayOfRecords track by singleRecord.id"
       tracker="item">

例如在父控制器上监听这些事件。

Demo

或者使用函数绑定,但以不同的方式,不使用隔离范围。

.directive('tracker', function() {
  return {
    restrict: 'A',
    link: function(scope, el, attr) {
      var setter = scope.$eval(attr.tracker);
      if(!angular.isFunction(setter)) return;
      setter({status:'ADDED', item:scope.$eval(attr.trackerItem)});


      scope.$on('$destroy', function() {
         setter({status:'REMOVED', item:scope.$eval(attr.trackerItem)});
      })
    }
  }
});

Demo


上面的问题是针对您的问题的,因为没有其他内置方法,请注意,如果您要真正找出添加/删除的项目,您也可以在控制器中通过区分 2 个列表来执行此操作。您可以尝试使用 lodash api,例如 _.unique,甚至可以使用简单的循环比较来查找结果。

  function findDif(oldList,newList){
       return {added:_.uniq(newList, oldList), removed:_.uniq(oldList, newList)};
 }

Demo

【讨论】:

  • 啊,谢谢,我稍后再试试。顺便说一句,如果这样的事情会对性能造成巨大影响,您是否知道?
  • @user193130 您必须尝试一下。但绝对最好的方法是在你的控制器本身中区分它。
  • @user193130 你到底希望如何?或者换句话说,您希望通知如何发生?函数调用事件或其他什么? Like this?
  • 啊,你读懂了我的想法,我希望将事件处理函数作为属性传递,哈哈。不过,主要是,我希望在arrayOfRecords 更改时仅触发一次事件,使用参数arrayOfAddedRecordsarrayOfRemovedRecords,而不是为每个修改的记录单独触发。现在想多了,估计不修改ngRepeat大概是不行了吧?我不得不说...我认为通过 DOM 更改进行跟踪实际上是解决这个问题的一种非常巧妙的方法,尽管它并不是我想要的。
  • 如此出色的答案教会了我更多关于 Angular 的知识,我别无选择,只能接受它:) 我没有时间深入研究 Angular 看看是否可以做我想做的事本来想要的,但如果我真的找到解决方案,我会回复你,以防你感兴趣。
【解决方案2】:

你可以改成:

<div ng-model="arrayOfRecords">
<some-element ng-repeat="singleRecord in arrayOfRecords track by singleRecord.id">
    <!-- stuff -->
</some-element>
</div>

只要 arrayOfRecords 发生变化,模型就会发生变化。

【讨论】:

    猜你喜欢
    • 2014-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-23
    • 1970-01-01
    • 2022-11-17
    相关资源
    最近更新 更多