210

我想用表调用一些针对 div 的 jQuery 函数。该表填充有ng-repeat.

当我调用它时

$(document).ready()

我没有结果。

$scope.$on('$viewContentLoaded', myFunc);

没有帮助。

在 ng-repeat 填充完成后,有什么方法可以立即执行功能?我已经阅读了有关使用 custom 的建议directive,但我不知道如何将它与 ng-repeat 和我的 div 一起使用...

4

15 回答 15

243

实际上,您应该使用指令,并且没有与 ng-Repeat 循环结束相关的事件(因为每个元素都是单独构建的,并且有自己的事件)。但是 a) 使用指令可能是您所需要的,并且 b) 您可以使用一些 ng-Repeat 特定属性来制作“on ngRepeat finished”事件。

具体来说,如果您只想为整个表设置样式/添加事件,则可以在包含所有 ngRepeat 元素的指令中使用。另一方面,如果您想专门处理每个元素,您可以在 ngRepeat 中使用指令,它会在创建后对每个元素起作用。

然后,您可以使用 、 和 属性来触发$index事件。所以对于这个 HTML:$first$middle$last

<div ng-controller="Ctrl" my-main-directive>
  <div ng-repeat="thing in things" my-repeat-directive>
    thing {{thing}}
  </div>
</div>

您可以使用如下指令:

angular.module('myApp', [])
.directive('myRepeatDirective', function() {
  return function(scope, element, attrs) {
    angular.element(element).css('color','blue');
    if (scope.$last){
      window.alert("im the last!");
    }
  };
})
.directive('myMainDirective', function() {
  return function(scope, element, attrs) {
    angular.element(element).css('border','5px solid red');
  };
});

在这个Plunker中查看它的实际效果。希望能帮助到你!

于 2012-11-20T11:51:09.967 回答
69

如果您只是想在循环结束时执行一些代码,这里有一个稍微简单的变体,不需要额外的事件处理:

<div ng-controller="Ctrl">
  <div class="thing" ng-repeat="thing in things" my-post-repeat-directive>
    thing {{thing}}
  </div>
</div>
function Ctrl($scope) {
  $scope.things = [
    'A', 'B', 'C'  
  ];
}

angular.module('myApp', [])
.directive('myPostRepeatDirective', function() {
  return function(scope, element, attrs) {
    if (scope.$last){
      // iteration is complete, do whatever post-processing
      // is necessary
      element.parent().css('border', '1px solid black');
    }
  };
});

观看现场演示。

于 2012-12-08T06:36:04.657 回答
65

不需要创建指令,尤其是为了有一个ng-repeat完整的事件。

ng-init为你施展魔法。

  <div ng-repeat="thing in things" ng-init="$last && finished()">

确保只有在最后一个元素被渲染到 DOM 时才会触发$lastfinished

不要忘记创建$scope.finished事件。

编码快乐!!

编辑:2016 年 10 月 23 日

如果您还想finished在数组中没有项目时调用该函数,那么您可以使用以下解决方法

<div style="display:none" ng-init="things.length < 1 && finished()"></div>
//or
<div ng-if="things.length > 0" ng-init="finished()"></div>

ng-repeat只需在元素顶部添加上述行。它将检查数组是否没有任何值并相应地调用函数。

例如

<div ng-if="things.length > 0" ng-init="finished()"></div>
<div ng-repeat="thing in things" ng-init="$last && finished()">
于 2016-06-17T10:42:55.547 回答
41

这是一个重复完成指令,它在为真时调用指定的函数。我发现被调用的函数必须在进行 DOM 操作之前使用间隔 = 0 的 $timeout,例如在渲染元素上初始化工具提示。jsfiddle:http: //jsfiddle.net/tQw6w/

在 $scope.layoutDone 中,尝试注释掉 $timeout 行并取消注释“不正确!” 行以查看工具提示中的差异。

<ul>
    <li ng-repeat="feed in feedList" repeat-done="layoutDone()" ng-cloak>
    <a href="{{feed}}" title="view at {{feed | hostName}}" data-toggle="tooltip">{{feed | strip_http}}</a>
    </li>
</ul>

JS:

angular.module('Repeat_Demo', [])

    .directive('repeatDone', function() {
        return function(scope, element, attrs) {
            if (scope.$last) { // all are rendered
                scope.$eval(attrs.repeatDone);
            }
        }
    })

    .filter('strip_http', function() {
        return function(str) {
            var http = "http://";
            return (str.indexOf(http) == 0) ? str.substr(http.length) : str;
        }
    })

    .filter('hostName', function() {
        return function(str) {
            var urlParser = document.createElement('a');
            urlParser.href = str;
            return urlParser.hostname;
        }
    })

    .controller('AppCtrl', function($scope, $timeout) {

        $scope.feedList = [
            'http://feeds.feedburner.com/TEDTalks_video',
            'http://feeds.nationalgeographic.com/ng/photography/photo-of-the-day/',
            'http://sfbay.craigslist.org/eng/index.rss',
            'http://www.slate.com/blogs/trending.fulltext.all.10.rss',
            'http://feeds.current.com/homepage/en_US.rss',
            'http://feeds.current.com/items/popular.rss',
            'http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml'
        ];

        $scope.layoutDone = function() {
            //$('a[data-toggle="tooltip"]').tooltip(); // NOT CORRECT!
            $timeout(function() { $('a[data-toggle="tooltip"]').tooltip(); }, 0); // wait...
        }

    })
于 2013-04-21T18:18:30.527 回答
30

这是一个简单的方法ng-init,甚至不需要自定义指令。它在某些情况下对我来说效果很好,例如需要在页面加载时将 ng 重复项的 div 自动滚动到特定项目,因此滚动功能需要等到ng-repeat完成对 DOM 的渲染才能触发。

<div ng-controller="MyCtrl">
    <div ng-repeat="thing in things">
        thing: {{ thing }}
    </div>
    <div ng-init="fireEvent()"></div>
</div>

myModule.controller('MyCtrl', function($scope, $timeout){
    $scope.things = ['A', 'B', 'C'];

    $scope.fireEvent = function(){

        // This will only run after the ng-repeat has rendered its things to the DOM
        $timeout(function(){
            $scope.$broadcast('thingsRendered');
        }, 0);

    };
});

请注意,这仅对您需要在 ng-repeat 最初呈现后调用一次的函数有用。如果您需要在更新 ng-repeat 内容时调用一个函数,那么您必须使用该线程上的其他答案之一和自定义指令。

于 2014-07-18T05:34:05.397 回答
28

作为 Pavel 的回答的补充,更具可读性和易于理解的内容是:

<ul>
    <li ng-repeat="item in items" 
        ng-init="$last ? doSomething() : angular.noop()">{{item}}</li>
</ul>

为什么你认为angular.noop首先存在......?

优点:

您不必为此编写指令...

于 2015-07-02T14:38:59.790 回答
21

ngInit使用Lodash 的方法可能更简单一些debounce,不需要自定义指令:

控制器:

$scope.items = [1, 2, 3, 4];

$scope.refresh = _.debounce(function() {
    // Debounce has timeout and prevents multiple calls, so this will be called 
    // once the iteration finishes
    console.log('we are done');
}, 0);

模板:

<ul>
    <li ng-repeat="item in items" ng-init="refresh()">{{item}}</li>
</ul>

更新

使用三元运算符还有更简单的纯 AngularJS 解决方案:

模板:

<ul>
    <li ng-repeat="item in items" ng-init="$last ? doSomething() : null">{{item}}</li>
</ul>

请注意,ngInit使用预链接编译阶段 - 即在处理子指令之前调用表达式。这意味着可能仍需要异步处理。

于 2014-11-21T10:06:14.250 回答
4

当您检查scope.$last变量以用setTimeout(someFn, 0). AsetTimeout 0是 javascript 中公认的技术,我directive必须正确运行。

于 2013-09-20T19:43:28.460 回答
4
<div ng-repeat="i in items">
        <label>{{i.Name}}</label>            
        <div ng-if="$last" ng-init="ngRepeatFinished()"></div>            
</div>

如果项目是重复中的最后一个,我的解决方案是添加一个 div 来调用函数。

于 2017-05-25T21:41:13.687 回答
4

我是这样做的。

创建指令

function finRepeat() {
    return function(scope, element, attrs) {
        if (scope.$last){
            // Here is where already executes the jquery
            $(document).ready(function(){
                $('.materialboxed').materialbox();
                $('.tooltipped').tooltip({delay: 50});
            });
        }
    }
}

angular
    .module("app")
    .directive("finRepeat", finRepeat);

将其添加到此 ng-repeat 的标签上后

<ul>
    <li ng-repeat="(key, value) in data" fin-repeat> {{ value }} </li>
</ul>

并且准备好将在 ng-repeat 结束时运行。

于 2016-05-17T04:32:12.590 回答
3

这是对其他答案中表达的想法的改进,以展示在使用声明性语法和隔离范围时如何访问 ngRepeat 属性($index、$first、$middle、$last、$even、$odd)(谷歌推荐的最佳实践)带有元素指令。注意主要区别:scope.$parent.$last.

angular.module('myApp', [])
.directive('myRepeatDirective', function() {
  return {
    restrict: 'E',
    scope: {
      someAttr: '='
    },
    link: function(scope, element, attrs) {
      angular.element(element).css('color','blue');
      if (scope.$parent.$last){
        window.alert("im the last!");
      }
    }
  };
});
于 2015-01-23T18:21:59.957 回答
2

我想添加另一个答案,因为前面的答案认为在 ngRepeat 完成后需要运行的代码是一个角度代码,在这种情况下,上面的所有答案都提供了一个伟大而简单的解决方案,其中一些比其他答案更通用,如果摘要生命周期阶段很重要,您可以查看Ben Nadel 的博客,但使用 $parse 而不是 $eval 除外。

但根据我的经验,正如 OP 所述,它通常在最终编译的 DOM 上运行一些 JQuery 插件或方法,在这种情况下,我发现最简单的解决方案是创建一个带有 setTimeout 的指令,因为 setTimeout 函数被推送到浏览器队列的末尾,它总是在一切都以角度完成之后,通常是 ngReapet,它在其父 postLinking 函数之后继续

angular.module('myApp', [])
.directive('pluginNameOrWhatever', function() {
  return function(scope, element, attrs) {        
    setTimeout(function doWork(){
      //jquery code and plugins
    }, 0);        
  };
});

对于想知道在这种情况下为什么不使用 $timeout 的人,它会导致另一个完全没有必要的摘要循环

于 2015-12-28T15:39:51.700 回答
1

在 ng-repeat 结束后,我不得不使用 MathJax 渲染公式,以上答案都没有解决我的问题,所以我做了如下。这不是一个很好的解决方案,但对我有用......

<div ng-repeat="formula in controller.formulas">
    <div>{{formula.string}}</div>
    {{$last ? controller.render_formulas() : ""}}
</div>
于 2016-10-03T17:43:18.810 回答
0

我在这里找到了一个很好实践的答案,但是仍然需要添加延迟

创建以下指令:

angular.module('MyApp').directive('emitLastRepeaterElement', function() {
return function(scope) {
    if (scope.$last){
        scope.$emit('LastRepeaterElement');
    }
}; });

将其作为属性添加到中继器,如下所示:

<div ng-repeat="item in items" emit-last-repeater-element></div>

据拉杜说:

$scope.eventoSelecionado.internamento_evolucoes.forEach(ie => {mycode});

对我来说它有效,但我仍然需要添加一个 setTimeout

$scope.eventoSelecionado.internamento_evolucoes.forEach(ie => {
setTimeout(function() { 
    mycode
}, 100); });
于 2018-04-20T16:32:10.913 回答
-4

如果您只是想更改类名以使其呈现方式不同,那么下面的代码就可以解决问题。

<div>
<div ng-show="loginsuccess" ng-repeat="i in itemList">
    <div id="{{i.status}}" class="{{i.status}}">
        <div class="listitems">{{i.item}}</div>
        <div class="listitems">{{i.qty}}</div>
        <div class="listitems">{{i.date}}</div>
        <div class="listbutton">
            <button ng-click="UpdateStatus(i.$id)" class="btn"><span>Done</span></button>
            <button ng-click="changeClass()" class="btn"><span>Remove</span></button>
        </div>
    <hr>
</div>

当我有类似的要求以 Strick trough 字体呈现购物清单中的购物项目时,此代码对我有用。

于 2015-04-20T04:35:51.423 回答