Javascript ng-repeat 完成事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13471129/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 12:10:17  来源:igfitidea点击:

ng-repeat finish event

javascriptjqueryangularjsangularjs-ng-repeatdocument-ready

提问by ChruS

I want to call some jQuery function targeting div with table. That table is populated with ng-repeat.

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

When I call it on

当我调用它时

$(document).ready()

I have no result.

我没有结果。

Also

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

doesn't help.

没有帮助。

Is there any way to execute function right after ng-repeat population completes? I've read an advice about using custom directive, but I have no clue how to use it with ng-repeat and my div...

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

回答by Tiago Rold?o

Indeed, you should use directives, and there is no event tied to the end of a ng-Repeat loop (as each element is constructed individually, and has it's own event). But a) using directives might be all you need and b) there are a few ng-Repeat specific properties you can use to make your "on ngRepeat finished" event.

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

Specifically, if all you want is to style/add events to the whole of the table, you can do so using in a directive that encompasses all the ngRepeat elements. On the other hand, if you want to address each element specifically, you can use a directive within the ngRepeat, and it will act on each element, after it is created.

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

Then, there are the $index, $first, $middleand $lastproperties you can use to trigger events. So for this HTML:

然后,还有$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>

You can use directives like so:

您可以像这样使用指令:

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');
  };
});

See it in action in this Plunker. Hope it helps!

在此Plunker 中查看它的运行情况。希望能帮助到你!

回答by karlgold

If you simply want to execute some code at the end of the loop, here's a slightly simpler variation that doesn't require extra event handling:

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

<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');
    }
  };
});


See a live demo.

观看现场演示。

回答by Vikas Bansal

There is no need of creating a directive especially just to have a ng-repeatcomplete event.

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

ng-initdoes the magic for you.

ng-init为你做魔法。

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

the $lastmakes sure, that finishedonly gets fired, when the last element has been rendered to the DOM.

$last做肯定的,那finished只有被炒鱿鱼,当最后一个元素已经被渲染到了DOM。

Do not forget to create $scope.finishedevent.

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

Happy Coding!!

快乐编码!!

EDIT: 23 Oct 2016

编辑:2016 年 10 月 23 日

In case you also want to call the finishedfunction when there is no item in the array then you may use the following workaround

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

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

Just add the above line on the top of the ng-repeatelement. It will check if the array is not having any value and call the function accordingly.

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

E.g.

例如

<div ng-if="things.length > 0" ng-init="finished()"></div>
<div ng-repeat="thing in things" ng-init="$last && finished()">

回答by Joseph Oster

Here is a repeat-done directive that calls a specified function when true. I have found that the called function must use $timeout with interval=0 before doing DOM manipulation, such as initializing tooltips on the rendered elements. jsFiddle: http://jsfiddle.net/tQw6w/

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

In $scope.layoutDone, try commenting out the $timeout line and uncommenting the "NOT CORRECT!" line to see the difference in the tooltips.

在 $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:

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...
        }

    })

回答by dshap

Here's a simple approach using ng-initthat doesn't even require a custom directive. It's worked well for me in certain scenarios e.g. needing to auto-scroll a div of ng-repeated items to a particular item on page load, so the scrolling function needs to wait until the ng-repeathas finished rendering to the DOM before it can fire.

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

<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);

    };
});

Note that this is only useful for functions you need to call one time after the ng-repeat renders initially. If you need to call a function whenever the ng-repeat contents are updated then you'll have to use one of the other answers on this thread with a custom directive.

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

回答by deostroll

Complementing Pavel's answer, something more readable and easily understandable would be:

补充 Pavel's answer,更易读和更容易理解的内容是:

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

Why else do you think angular.noopis there in the first place...?

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

Advantages:

好处:

You don't have to write a directive for this...

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

回答by Pavel Horal

Maybe a bit simpler approach with ngInitand Lodash's debouncemethod without the need of custom directive:

也许使用ngInitLodash 的debounce方法更简单一点,不需要自定义指令:

Controller:

控制器:

$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);

Template:

模板:

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


Update

更新

There is even simpler pure AngularJS solution using ternary operator:

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

Template:

模板:

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

Be aware that ngInituses pre-link compilation phase - i.e. the expression is invoked before child directives are processed. This means that still an asynchronous processing might be required.

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

回答by Cody

It may also be necessary when you check the scope.$lastvariable to wrap your trigger with a setTimeout(someFn, 0). A setTimeout 0is an accepted technique in javascript and it was imperative for my directiveto run correctly.

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

回答by JoshuaDavid

This is an improvement of the ideas expressed in other answers in order to show how to gain access to the ngRepeat properties ($index, $first, $middle, $last, $even, $odd) when using declarative syntax and isolate scope (Google recommended best practice) with an element-directive. Note the primary difference: scope.$parent.$last.

这是对其他答案中表达的想法的改进,以展示如何在使用声明性语法和隔离范围时访问 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!");
      }
    }
  };
});

回答by scotty3

<div ng-repeat="i in items">
        <label>{{i.Name}}</label>            
        <div ng-if="$last" ng-init="ngRepeatFinished()"></div>            
</div>

My solution was to add a div to call a function if the item was the last in a repeat.

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