-1

I'm facing some serious performance issues in my angular app, surely due to my bad ng-repeat implementation but I don't know how to do better. I've tried some other combinations but none give me the result I want, nor better performance. There have been some infinite loops, undefined variables due to asynch and $digest aborting. This is how it should be looking (so that's the working result, but not optimized for now) : http://scr.hu/0ei9/8bpw9

Days with blue cells = user is present, red cell = absent. Beneath are the "shifts" per day (each shift can be done on various days).

When I console.log some of the functions, they are called way too many times than needed, for example isPresent (for checking if the user submited the day as available) is called 5x180 (180 being probably 5 users x 30 days of month) and getDayOfWeek (used in template for the shifts row) 28+840+812...there are 10 shifts.

Whereas I would normally need to call isPresent only 1x180 for all cells and getDayOfWeek 1x30 days of month for one shifts row. That said, I don't really get why its called sooo many times and how to optimize it.

In addition, when I click on a blue cell, the setShift() function is called. I copied the function here but don't analyze it, I only wanted to show that it nowhere calls any of the previous functions, however I console.log an impressive 28x "days of the week" + 180 "is present" and + 812 "day of the week". No Idea where it comes from... to be frank, everything i click calls this same amout - if I change the month, year, click on an independent button...

I omitted some classes and css for better code reading.

Thanks for your help.

Edit

after commenting and decommenting some of the code I see that the most of those unwanted logs when I call the setShift() function come from the last sub-call : showPopover() where I open a $modal. When commented, there is like 1/3 of what I'm used to see. Before the modal appears there is the rest of this stuff. Furthermore I think that the temlpateUrl might be the cause because when commented it does not log all those houndreds of 'is present' and 'day of week'. And when I click anywhere on the modal, it recalls all those functions. Any ideas?

JS angular functions

            $scope.isPresent = function(day, month, year, userId) {
              console.log('is present')
              var date = new Date(year, month - 1, day + 1)
              var day = moment(date).format("D-M-YYYY");
              for (var i = 0; i < $scope.presences.length; i++) {
                var presentDay = moment($scope.presences[i].start).format("D-M-YYYY")
                if (presentDay == day && userId == $scope.presences[i].coursierId) {
                  return true
                }
              }
            }

            $scope.getDayOfWeek = function(day, month, year) {
                console.log('day of the week')
                var date = new Date(parseInt(year), month - 1, day + 1)
                var dayId = date.getDay();
                return dayId;
              }
              /*
                used for a limited ng-repeat
              */
            $scope.getTimes = function(n) {
              return new Array(n);
            };


            /*
              Shows a list of sorted out shifts with corresponding
              hours, cities and capabilities of coursier.
            */
            $scope.setShift = function(day, month, year, userId, event) {
              var date = new Date(year, month - 1, day)
              var day = moment(date).format("D-M-YYYY");
              var dayOfWeek = moment(date).day()
                //SORT SHIFTs BY DAY OF WEEK clicked
              var day_shifts = $scope.sortShiftByDayOfWeek(dayOfWeek)
                //console.log(day_shifts)
                //check if the day clicked is an dispo present day
              for (var i = 0; i < $scope.presences.length; i++) {
                var dispoDay = moment($scope.presences[i].start).format("D-M-YYYY")
                  //if yes, check the presence user id and the cell of user clicked
                if (dispoDay == day) {
                  //then get all the shifts that fit into this coursier's time range
                  if ($scope.presences[i].coursierId == userId) {
                    var dispo = $scope.presences[i];
                    var dispoHours = $scope.getDispoHoursAndDay(dispo);
                    var time_shifts = $scope.compareDiposHoursAndShift(dispoHours, day_shifts);
                    //then sort the shifts by the dispo's and shift's cities
                    var time_city_shifts = $scope.compareDispoCityAndShift(time_shifts, dispo);
                    var time_city_able_shifts = $scope.compareUserAndShift(time_city_shifts, userId);
                    $scope.showPopover(time_city_able_shifts, event);
                  }
                };
              };
            }
###Calendar table
<table class="table table-bordered">
  <!--days of month-->
  <tr class="mainHeader">
    <th>coursier/jour</th>
    ##calendar.days = 30 days of month, for example
    <th class="monthDay" ng-repeat=" numDay in [] | range: calendar.days">{{$index+1}} {{calendar.daysNames[$index]}}
    </th>
  </tr>

  <!-- user name and days -->
  <tr ng-repeat="user in coursiers">
    <!-- <td class="coursierName">nom coursier</td> -->
    <td>
      <a href="#"> {{user.name}}</a> 
    </td>
    <td ng-click="setShift($index+1, monthNum,year, user._id, $event)" ng-repeat="numDay in getTimes(calendar.days) track by $index" ng-class=" isPresent($index, monthNum,year, user._id) == true ?   
           'present' : isAbsent($index, monthNum,year, user._id) == true ?  
           'absent' : '' ">
    </td>
  </tr>

  <tr>
    <td>Shifts par jour</td>
    <td class="shiftsParJourCell" ng-repeat="day in getTimes(calendar.days) track by $index">
      <span ng-repeat="shift in shifts">
                <span ng-repeat="jour in shift.jours">
                  {{jour.id == 
                    getDayOfWeek($parent.$parent.$index, monthNum, year) ? shift.nom : ''}}
                </span>
      </span>
    </td>
  </tr>
</table>
ginold
  • 103
  • 1
  • 10
  • I'd start by getting rid of as many function calls in the ng-repeat as possible by pre-processing the data for the view each time it changes rather than processing it during the digest cycle. – Kevin B Jun 23 '15 at 19:28
  • Take a look at [this question and its answer](http://stackoverflow.com/questions/14973792/why-angularjs-will-invoke-function-name-twice). Your view is probably getting evaluated multiple times to confirm that it hasn't changed, which is why you're seeing that many function calls. As per Kevin B's recommendation, try to get rid of the method calls by using a watcher that updates your data directly. – Agop Jun 23 '15 at 19:39
  • Also, @ginold, if you can create a Plunker/jsFiddle, we may be able to better help. It's hard to optimize your code without a working example. – Agop Jun 23 '15 at 19:40
  • use one time binding expressions `::getTimes(calendar.days)` on ng-repeat and `{{::` on interpolation, to make it less call (angular 1.3+) – YOU Jun 24 '15 at 00:57
  • after commenting and decommenting some of the code I see that the most of those unwanted logs when I call the setShift() function come from the last sub-call : showPopover() where I open a $modal. When commented, there is like 1/3 of what I'm used to see. Before the modal appears there is the rest of this stuff. Furthermore I think that the temlpateUrl might be the cause because when commented it does not log all those houndreds of 'is present' and 'day of week'. And when I click anywhere on the modal, it recalls all those functions. Any ideas? – ginold Jun 24 '15 at 12:44
  • thats one of behavior of angular dirty checking, function inside {{}} will get called any times angular want. mostly proportional to watchers count. – YOU Jun 24 '15 at 13:00

1 Answers1

0

After a while, in my case the problem was that I wasn't using directives. The scopes were having unwanted interactions (still don't know why) but after separing my html in angular directives there are no issues so far.

ginold
  • 103
  • 1
  • 10