Подтвердить что ты не робот

Директива angularjs: $rootScope: ошибка infdig

Я пытаюсь создать директиву разбиения на страницы с помощью angularjs 1.2.15:

Это мое мнение:

<input type="text" ng-model="filter.user">
<input type="number" ng-model="filter.limit" ng-init="filter.limit=5">
<ul>
  <li ng-repeat="user in (filteredUsers = (users | orderBy:order:reverse | filter:filter.user ) | limitTo: filter.limit)" ng-click="showDetails(user)">
    {{user.id}} / {{user.firstname}} {{user.lastname}}
  </li>
</ul>
<div pagination data='filteredUsers' limit='filter.limit'></div>

и вот моя директива разбиения на страницы:

app.directive('pagination', function(){
  return {
    restrict: 'A',
    templateUrl: 'partials/pagination.html',
    scope: {
      data: '=data',
      limit: '=limit'
    }
  }
})

Все работает отлично, без директивы разбиения на страницы. Однако с моей новой директивой, как только я загружаю страницу, я получаю ошибку $rootScope:infdig, которую я не понимаю, поскольку директива не делает ничего, чтобы манипулировать данными, которые могут закончиться бесконечным циклом.
В чем проблема и как я могу ее решить? Спасибо!

Update:
Вот контроллер и ресурс.
Контроллер:

usersModule.controller('usersController',
  function ($scope, Users) {
    function init(){
      $scope.users = Users.get();
    }
    init();
})

Ресурс (получает пользователей как массив из REST API):

app.factory('Users', function($resource) {
  return $resource('http://myrestapi.tld/users', null,{
       'get': { method:'GET', isArray: true, cache: true }
   });
});

Обновление 2

Вот демо: http://plnkr.co/edit/9GCE3Kzf21a7l10GFPmy?p=preview
Просто введите букву (например, "f" ) в левый вход.

4b9b3361

Ответ 1

Проблема не в директиве, она находится в $watch, который создает директива. Когда вы отправляете filterUsers в директиву, директива создает следующую строку:

$scope.$watch("filteredUsers", function() {
    // Directive Code...
});

Обратите внимание в следующем примере, как мы воспроизводим его без директивы: http://plnkr.co/edit/uRj19PyXkvnLNyh5iY0j

Причина, по которой это происходит, заключается в том, что вы меняете фильтрованные пользователи каждый раз, когда выполняется дайджест (поскольку вы помещаете назначение в инструкцию ng-repeat).

Чтобы исправить это, вы можете рассмотреть возможность просмотра и фильтрации массива в контроллере с дополнительным параметром "true" для $watch:

$scope.$watch("users | orderBy:order:reverse | filter:filter.user", function(newVal) {
    $scope.filteredUsers = newVal;
}, true);

Вы можете проверить решение здесь: http://plnkr.co/edit/stxqBtzLsGEXmsrv3Gp6

$watch без дополнительного параметра (true) сделает простое сравнение с объектом, и поскольку вы создаете новый массив в каждом цикле дайджеста, объект всегда будет отличаться. Когда вы передаете истинный параметр функции $watch, это означает, что он действительно сделает глубокое сравнение с объектом, который возвращается перед запуском $watch снова, поэтому, даже если у вас есть разные экземпляры массивов, которые имеют одинаковые данные, он будет считайте их равными.

Ответ 2

Быстрое исправление заключается в том, чтобы добавить директиву $watchCollection в директиве вместо двухсторонней привязки.

app.directive('pagination', function($parse){
  return {
    restrict: 'A',
    template: '',
    scope: {
      limit: '=limit'
    },
    link: function(scope, elem, attrs) {
      var dataExpr = $parse(attrs.data);
      var deregister = scope.$parent.$watchCollection(dataExpr, function(val) {
        scope.data = val;
      });
      scope.$on('$destroy', deregister);
    }
  }
})

$watchCollection контролирует содержимое массива, а не ссылку на него.

Посмотрите, как работает здесь.

Вообще говоря, мне не нравятся такие выражения:

filteredUsers = (users | orderBy:order:reverse | filter:filter.user )

внутри просмотров. Представления должны отображать только свойства $scope, а не создавать новые.

Ответ 3

Эта ошибка может быть удалена, чтобы очистить историю браузера от установки. Я получил одну и ту же проблему и применил много решений для решения этой проблемы, но не могу решить. Но когда я удаляю историю браузера и кеш, эта проблема решена. Пусть это поможет вам.