ng-repeat finish event

2018-12-31 04:20发布

I want to call some jQuery function targeting div with table. That table is populated with 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...

15条回答
无与为乐者.
2楼-- · 2018-12-31 05:00

Maybe a bit simpler approach with ngInit and Lodash's debounce method without the need of custom directive:

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:

Template:

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

Be aware that ngInit uses 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.

查看更多
姐姐魅力值爆表
3楼-- · 2018-12-31 05:02

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

ng-init does the magic for you.

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

the $last makes sure, that finished only gets fired, when the last element has been rendered to the DOM.

Do not forget to create $scope.finished event.

Happy Coding!!

EDIT: 23 Oct 2016

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

<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-repeat element. It will check if the array is not having any value and call the function accordingly.

E.g.

<div ng-if="things.length > 0" ng-init="finished()"></div>
<div ng-repeat="thing in things" ng-init="$last && finished()">
查看更多
残风、尘缘若梦
4楼-- · 2018-12-31 05:02

Here's a simple approach using ng-init that 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-repeat has finished rendering to the DOM before it can fire.

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

查看更多
深知你不懂我心
5楼-- · 2018-12-31 05:03
<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.

查看更多
梦醉为红颜
6楼-- · 2018-12-31 05:04

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.

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.

Then, there are the $index, $first, $middle and $last properties you can use to trigger events. So for this 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!

查看更多
深知你不懂我心
7楼-- · 2018-12-31 05:11

I did it this way.

Create the directive

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

After you add it on the label where this ng-repeat

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

And ready with that will be run at the end of the ng-repeat.

查看更多
登录 后发表回答