ng-repeat结束事件
我想调用一些jQuery函数针对div与表。 该表使用ng-repeat
填充。
当我打电话
$(document).ready()
我没有结果。
也
$scope.$on('$viewContentLoaded', myFunc);
没有帮助。
ng-repeat群体完成后,是否有任何方法可以执行? 我已阅读关于使用自定义directive
的build议,但我不知道如何使用ng-repeat和我的div …
事实上,你应该使用指令,并且没有任何事件绑定到ng-Repeat循环的结尾(因为每个元素都是单独构build的,并且具有它自己的事件)。 但是a)使用指令可能是你所需要的,b)有几个ng-repeat特定的属性可以用来使你的“在ngRepeat已完成”事件上。
具体而言,如果您只想将样式/事件添加到整个表格中,则可以在包含所有ngRepeat元素的指令中使用。 另一方面,如果你想专门针对每个元素,你可以在ngRepeat中使用一个指令,并且在每个元素被创build之后,它会作用于每个元素。
然后,可以使用$index
, $first
, $middle
和$last
来触发事件。 所以对于这个HTML:
<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行动。 希望它有帮助!
如果你只是想在循环结尾执行一些代码,这里有一个稍微简单的变化,不需要额外的事件处理:
<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'); } }; });
看现场演示。
这是一个repeat-done指令,当true时调用指定的函数。 我发现被调用的函数在执行DOM操作之前必须使用$ timeout和interval = 0,比如初始化渲染元素的工具提示。 jsFiddle: http : //jsfiddle.net/tQw6w/
在$ scope.layoutDone中,尝试注释$ timeout行并取消注释“NOT CORRECT!” 行来查看工具提示的区别。
<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... } })
没有必要创build一个指令,特别是只有一个ng-repeat
完成的事件。
ng-init
为你做了这个魔术。
<div ng-repeat="thing in things" ng-init="$last && finished()">
$last
一个元素可以确保,只有当最后一个元素已经被渲染到DOM的时候才完成。
不要忘记创build$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()">
这是一个使用ng-init
的简单方法,甚至不需要自定义指令。 在某些情况下,对于我来说这很有效,比如在页面加载时需要自动滚动一个ng-repeated的项目到一个特定的项目,所以滚动function需要等到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内容被更新的时候调用一个函数,那么你必须使用自定义指令来使用这个线程上的其他答案之一。
作为帕维尔答案的补充,更可读和易于理解的东西是:
<ul> <li ng-repeat="item in items" ng-init="$last ? doSomething() : angular.noop()">{{item}}</li> </ul>
你为什么还觉得angular.noop
是第一位的?
优点:
你不必为此写一个指令…
用ngInit
和Lodash的ngInit
方法可能会更简单ngInit
,而不需要自定义指令:
控制器:
$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解决scheme:
模板:
<ul> <li ng-repeat="item in items" ng-init="$last ? doSomething() : null">{{item}}</li> </ul>
请注意, ngInit使用预链接编译阶段 – 即在处理子指令之前调用expression式。 这意味着仍然可能需要asynchronous处理。
当你检查scope.$last
variables来用setTimeout(someFn, 0)
来包装你的触发器的时候也是很有必要的。 一个setTimeout 0
是在javascript中被接受的技术,这是我的directive
正确运行的必要条件。
这是对其他答案中expression的想法的改进,以便展示如何在使用声明性语法和隔离范围时显示如何访问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!"); } } }; });
我想添加另一个答案,因为前面的答案认为,在ngRepeat完成后需要运行的代码是一个angular码,在这种情况下,所有的答案都给出了一个很好和简单的解决scheme,比其他更通用,以及万一重要的消化生命周期阶段,你可以看看Ben Nadel的博客 ,除了使用$ parse而不是$ eval。
但根据我的经验,正如OP所述,它通常在finnaly编译的DOM上运行一些JQuery插件或方法,在这种情况下,我发现最简单的解决scheme是使用setTimeout创build一个指令,因为setTimeout函数被推送到浏览器队列的尾部,它的所有事情都是在angular度完成之后进行的,通常是在父节点之后继续的ngReapet postLinking函数
angular.module('myApp', []) .directive('pluginNameOrWhatever', function() { return function(scope, element, attrs) { setTimeout(function doWork(){ //jquery code and plugins }, 0); }; });
对于那些想知道为什么不使用$ timeout的人,它会导致另一个完全不必要的摘要循环
我这样做了。
创build指令
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结束时运行。
<div ng-repeat="i in items"> <label>{{i.Name}}</label> <div ng-if="$last" ng-init="ngRepeatFinished()"></div> </div>
我的解决scheme是添加一个div来调用一个函数,如果该项目是重复的最后一个。
在ng-repeat结束后,我不得不使用MathJax来渲染公式,上面的答案都没有解决我的问题,所以我在下面做了。 这不是一个很好的解决scheme ,但为我工作…
<div ng-repeat="formula in controller.formulas"> <div>{{formula.string}}</div> {{$last ? controller.render_formulas() : ""}} </div>
如果你只是想改变类名,所以它会呈现不同的方式,下面的代码会做的伎俩。
<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字体在我的购物清单中呈现购物物品。