简体   繁体   中英

avoid “$digest already in progress” error

I've defined the following directive which wraps the pagination directive provided by UI Bootstrap

angular.module('my-module')
  .directive('myPagination', ['$filter', '$window', function ($filter, $window) {

    return {
      restrict: 'EA',
      scope: {
        itemsPerPage: '=',
        totalItems: '=',
        page: '='
      },
      link: function (scope, element, attrs) {
        scope.hiddenElement = true;
        var totalMargin = 200, widthByElement = 41;

        scope.getWindowDimensions = function () {
          return {
            'w': element.width()
          };
        };

        scope.$watch(scope.getWindowDimensions, function (newWidth, oldWidth) {
          // calculate how many page buttons fit in the pagination horizontal bar
          scope.maxSize = parseInt($filter('number')((newWidth.w - totalMargin) / widthByElement, 0));
        }, true);

        angular.element($window).bind('resize', function () {
          // "$digest already in progress" thrown by the following line
          scope.$apply();  
        });

      },
      template: '<div class="text-center paginationSelfCare"  ng-show="totalItems > itemsPerPage">' +
      '<pagination ng-show="totalItems/itemsPerPage <= maxSize" total-items="totalItems" items-per-page="itemsPerPage" ng-model="page" max-size="maxSize" class="pagination pagination-sm" ></pagination>' +
      '<pagination ng-show="totalItems/itemsPerPage > maxSize" total-items="totalItems" boundary-links="true" direction-links="true" previous-text="<" next-text=">" first-text="<<" last-text=">>" items-per-page="itemsPerPage" ng-model="page" max-size="maxSize" class="pagination pagination-sm" ></pagination>' +
      '</div>'
    };
  }]);

If this directive is running in one browser tab (A), and I switch to a different tab (B), then when I switch back to A, I see the following error in the browser console:

Error: [$rootScope:inprog] $digest already in progress http://errors.angularjs.org/1.4.4/ $rootScope/inprog?p0=%24digest minErr/<@ http://127.0.0.1:9000/bower_components/angular/angular.js:68:12 beginPhase@ http://127.0.0.1:9000/bower_components/angular/angular.js:16273:1 $RootScopeProvider/this.$gethttp://127.0.0.1:9000/bower_components/angular/angular.js:16014:11 .link/<@ http://127.0.0.1:9000/scripts/directives/pagination.js:30:11

Line 30 of pagination.js is the line marked with a comment above

scope.$apply(); 

Is there something I can check before calling scope.$apply(); in order to avoid this issue? I'm running Angular version 1.4.4

You could try $socpe.$applyAsync() instead of $scope.$apply() which will never conflict with currently running digest cycle.

$apply on $scope directly tried to run digest cycle when you run it directly. It doesn't check for if any digest cycle is in progress, and you run the digest loop, it throws $digest already in progress .

Though you could fix this issue by using wrapping your code $timeout function, but I'd prefer to go for $applyAsync method of scope .

$timeout does run digest cycle but before running it, it checks for if any digest is in progress, then run place this digest cycle call in queue and run it once the running digest cycle complete.

$applyAsync is a performance wise improved version of running digest cycle, when you ran this method, it first check for any digest cycle is running or not. if there any running digest cycle found it place that block of in that digest cycle (That means you reduced one digest cycle).

Reference Link

Your watch is very strange. This is usual way:

angular.element($window).bind('resize', function () {
  // There are a lot of resize events, we do not need to change smth on each 
  // Once per some time is ok.
  if (attrs.lastResize) {
      $timeout.cancel(attrs.lastResize)
  }

  attrs.lastResize = $timeout(function() {
      // actual code like
      // like scope.maxSize = calc();
  }, 75)
});

You dont need apply here, since you have $timeout.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM