3

I have a code which makes an ajax call and gets a json object from which the ng-repeat's are rendered. Once this all is rendered I want to call a function which binds some events on rendered element.

<div ng-repeat="list in arr | filter: {DegreeName: 'xyz'}">
    <div class="saveprogram">save program</div>
</div>
<div ng-repeat="list in arr | filter: {DegreeName: 'abc'}">
    <div class="saveprogram">save program</div>
</div>
<div ng-repeat="list in arr | filter: {DegreeName: 'test'}">
    <div class="saveprogram">save program</div>
</div>

Once all the above ng-repeat are rendered, I want to attach some events on it. I tried

$window.onload = function(){
    //someevent
    $(".saveprogram")
} 

This works but it has some issues in IE. Can someone help me with some directive which runs once all the ng-repeat are rendered

Note: I have gone through many posts and tried but that didn't help. I would have used ng-click but this is an existing code and very complex. It has lot of things in it. So I don't want to rewrite everyhing again. And calling function every time on ng-click I didnt find it good. I just want to run the function once, which does all bindings

Susheel Singh
  • 3,824
  • 5
  • 31
  • 66
  • That answer solves your problem. http://stackoverflow.com/questions/15207788/calling-a-function-when-ng-repeat-has-finished – Tiago Fabre Jul 09 '16 at 20:28
  • I already saw this but this is for single ng-repeat I think – Susheel Singh Jul 09 '16 at 20:29
  • ok, if it works for one ng-repeat it works for every. You just should call a method that will count how many times ng repeat finished and when it be 3, you make something... – Tiago Fabre Jul 09 '16 at 20:32
  • isn't there something better than this. Because its like hardcording, counting and all those – Susheel Singh Jul 09 '16 at 20:33
  • it is not hard and I already implemented what I sad for you, it is just copy and paste – Tiago Fabre Jul 09 '16 at 20:39
  • is that useful to you? (I edited the answer) – Tiago Fabre Jul 09 '16 at 21:03
  • What exactly are you trying to do after? Why aren't you binding events using angular in the first place? This all sounds like an XY problem – charlietfl Jul 09 '16 at 22:12
  • Strongly suggest you read: [Thinking in angular if I have a jQuery background](http://stackoverflow.com/questions/14994391/thinking-in-angularjs-if-i-have-a-jquery-background) – charlietfl Jul 09 '16 at 22:32
  • @charlietfl This is very big code which was written already, so I dont want to change it. I just want to bind the event by runing that function..or else I would have directly used ng-click – Susheel Singh Jul 10 '16 at 08:19
  • Good luck. This is totally the wrong approach to building angular apps and will likely give you unexpected problems – charlietfl Jul 10 '16 at 10:28
  • @charlietfl I know but its client's requirement ;) This is the only jquery piece in my code everything else is just modifying the object to get the view – Susheel Singh Jul 10 '16 at 10:35

5 Answers5

4

Directive

You can just insert that code before your controller and it will work

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

Notice that I didn't use .ready() but rather wrapped it in a $timeout. $timeout makes sure it's executed when the ng-repeated elements have REALLY finished rendering (because the $timeout will execute at the end of the current digest cycle -- and it will also call $apply internally, unlike setTimeout). So after the ng-repeat has finished, we use $emit to emit an event to outer scopes (sibling and parent scopes).

And then in your controller, you can catch it with $on:

$scope.counter = 0;
$scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) {
    $scope.counter++;
    if($scope.counter == 3){
        //CallYourMethodHere()
        $scope.counter = 0;
    } 
});

With html that looks something like this:

<div ng-repeat="item in items" on-finish-render="ngRepeatFinished">
    <div>{{item.name}}}<div>
</div>

if directives are unclear for you, take a look on this docs:

https://docs.angularjs.org/guide/directive

Reference: Answere based on Calling a function when ng-repeat has finished Since the user already saw this answre but still with problems. (I just added the counter inside the controller).

Community
  • 1
  • 1
Tiago Fabre
  • 739
  • 5
  • 18
1

You should create a directive and include the directive into Your ng-repeat element.

<div ng-repeat="list in arr | filter: {DegreeName: 'test'}">
    <div class="saveprogram" directive-to-Do-something>save program</div>
</div>

Then when the class element saveprogram is created and loaded the directive will do the job. That's the purpose of the directives: attach new behavior to a specific element, that I understood is what You want.

mario ruiz
  • 880
  • 1
  • 11
  • 28
0

Keeping with jQuery style event registrations, you could use...

$window.onload = function(){
    $('document').on('click', '.saveprogram', function(){
         // handle the click event here
         // this will be the clicked element
    })
}

Substituting the event you would like to handle.

You'll only need to do this once and you won't have to wait until the `ng-repeat finishes rendering

phuzi
  • 12,078
  • 3
  • 26
  • 50
  • 1
    To use jquery outside angular directives isn't a good practice. Take a look on this: http://stackoverflow.com/questions/14994391/thinking-in-angularjs-if-i-have-a-jquery-background?rq=1 – Tiago Fabre Jul 09 '16 at 22:22
  • Agreed, but wanted to give OP an alternative to the other answers. – phuzi Jul 10 '16 at 00:08
0

The proper angular approach is to use built in event directives like ng-click.

Whatever you do in that event handler in controller would then update scope model and server if needed

<div ng-repeat="list in arr | filter: {DegreeName: 'abc'}">
    <div class="saveprogram" ng-click="saveProgram(list)">save program</div>
</div>

if you need to use a plugin on those elements then create a custom directive where each element is exposed as jQuery object when jQuery is included in page before angular

charlietfl
  • 170,828
  • 13
  • 121
  • 150
0

Well, I don't know what's your purpose to do this, but for sure you don't need to create a directive for this. You could create a function and call it in every $last element of ngRepeat, then increment a variable and when it becomes 3, you can do what you want, this way:

ng-init="$last && increment()"

Here's a demonstration:

(function() {
  "use strict";
  angular.module('app', [])
    .controller('mainCtrl', function($scope) {
      $scope.items = [];
      for (var i = 1; i <= 50; i++) {
        $scope.items.push('Item ' + i);
      }

      var inc = 0;
      $scope.increment = function() {
        inc++;
        if (inc == 3) {
          // do something
          console.log(inc);
        }
      }
    });

})();
<html ng-app="app">

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
</head>

<body ng-controller="mainCtrl">
  <div ng-repeat="item in items" ng-init="$last && increment()">
    <div class="saveprogram">save program</div>
  </div>
  <div ng-repeat="item in items" ng-init="$last && increment()">
    <div class="saveprogram">save program</div>
  </div>
  <div ng-repeat="item in items" ng-init="$last && increment()">
    <div class="saveprogram">save program</div>
  </div>
</body>

</html>
developer033
  • 24,267
  • 8
  • 82
  • 108