【问题标题】:Firing an event when ng-repeat has finished it's work当 ng-repeat 完成它的工作时触发一个事件
【发布时间】:2015-11-27 13:38:39
【问题描述】:

在 ng-repeat 完成更改 dom 后,我需要更新特定元素的样式。这是我的挑战。当我将项目添加到模型时,我编写的用于触发 ng-repeat 工作的指令很好,但是当我从项目中删除对象时它不会被调用。

我添加了一个从列表中随机推送和弹出数据的函数。您将看到 pop 不会触发 ng-repeat 指令调用。无论如何要解决这个问题?

var module = angular.module('testApp', [])
.directive('onFinishRender', function ($timeout) {
return {
    restrict: 'A',
    link: function (scope, element, attr) {
        if (scope.$last === true) {
            scope.$evalAsync(attr.onFinishRender);
        }
    }
}
});

Fiddle Link

【问题讨论】:

    标签: javascript angularjs angularjs-ng-repeat


    【解决方案1】:

    你可以这样做:

    <p ng-repeat="t in ta" on-finish-render="test()"
        ng-init="myFunction($last, t)">{{t}}</p>
    
    $scope.myFunction = function(isLast, item){
        if(isLast)
            console.log(item)
    }
    

    ng-init 是一个在创建元素时运行的属性。
    $last 是一个布尔值,如果当前元素是 ng-repeat 中的最后一个元素,则为 true

    Updated Fiddle

    【讨论】:

    • 我做了一个快速检查,ng-init 在我删除一个元素时没有被触发。这本质上是我需要更新 dom 高度的事件。
    • 嗯,这可能是因为现有元素没有更新。我不太确定如何解决这个问题。
    • 是的。只要我将东西添加到数组中,该指令就可以正常工作。这是我需要帮助的移除
    【解决方案2】:

    为什么不使用 $watch?

    $scope.$watch('ta', function (newVal, oldValue) {
        if(oldValue.length > 0)
        {
            var i = 0; // do something
        }
    }, true);
    

    这样您可以控制何时向数组推送或弹出项目。

    http://jsfiddle.net/W8nhv/114/

    【讨论】:

    • if(oldValue.length !== newValue.length),那么这应该可以工作。
    • 在 ng-repeat 完成操作后,我实际上需要 dom 元素的高度。这将在 dom 操作结束之前触发。
    • 您想要删除列表项后整个列表的高度吗?
    • @Gen4ik 是的,父元素的高度。我在另一个 ng-repeat 中也有这个 ng-repeat。因此,我不确定对象的名称是否可以观察个别名称的变化。本质上是在寻找一种不是很肮脏的方式来实现这一目标。
    【解决方案3】:

    好吧,你添加一个元素数组。因此,它在渲染时肯定会触发自己的link() 函数。请记住,您为 array 中的每个 element 创建了一个 onFinishRender directive,并具有自己的 scope .

    数组长度改变后你想做什么?也许指令不是正确的尝试。

    【讨论】:

    • 没错。我不得不使用过滤器。
    【解决方案4】:

    简单有效的方法

    <li ng-repeat="data in dataList" ng-init="$last && $parent.myOnFinishHandler();" ></li>
    

    $parent指向datalist存储的范围

    angular.module("abc", []).controller('mc', function($scope) {
      $scope.dataList = ["abc", "123", "xyz", "orange", "apple"];
      $scope.myHandler = function() {
        console.log("render finish ");
      }
    
    });
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <div ng-app="abc">
      <ul ng-controller="mc">
        <li ng-repeat="data in dataList" ng-init="$last && $parent.myHandler();"> {{data}} </li>
      </ul>
    </div>

    【讨论】:

      【解决方案5】:

      我在one of the other solutions 中找到了解决方案。

      事实证明没有很好的方法来实现这个功能。我编写了一个过滤器,它基本上可以完成我想要它做的事情。基础是:

      app.filter('ngRepeatFinish', function($timeout){
          return function(data, scope){
              //var scope = this;
              var flagProperty = '__finishedRendering__';
              if(!data[flagProperty]){
                  Object.defineProperty(
                      data, 
                      flagProperty, 
                      {enumerable:false, configurable:true, writable: false, value:{}});
                  $timeout(function(){
                          delete data[flagProperty];                        
                          scope.$emit('ngRepeatFinished');
                      },0,false);                
              }
              return data;
          };
      })
      

      上面的过滤器为每个创建的元素广播,我可以根据控制器中的监听事件运行我的手表。

      $scope.$on('ngRepeatFinished', function() {
          //Work thy magic
      })
      

      要调用这个指令,我必须从 HTML 传递范围,然后通过 ngRepeatFinish 前面的 this 来实现。

      <div ng-repeat="item in (items | ngRepeatFinish:this)"></div>
      

      【讨论】:

        猜你喜欢
        • 2012-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-21
        • 2012-09-22
        • 2016-10-07
        • 1970-01-01
        相关资源
        最近更新 更多