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

Angular групповой фильтр

После angular.js условной разметки в ng-repeat я попытался создать настраиваемый фильтр, который группирует. Я сталкивался с проблемами, связанными с идентификацией объектов, и модель наблюдалась за изменениями, но я подумал, что я, наконец, прибил ее, так как никаких ошибок больше не появлялось в консоли.

Оказывается, я был неправ, потому что теперь, когда я пытаюсь объединить его с другими фильтрами (для разбивки на страницы), так

<div ng-repeat="r in blueprints | orderBy:sortPty | startFrom:currentPage*pageSize | limitTo:pageSize | group:3">
      <div ng-repeat="b in r">

Я получаю ужасные "10 $digest() итерации, достигнутые. Прерывание!" сообщение об ошибке снова.

Вот мой групповой фильтр:

filter('group', function() {
  return function(input, size) {
    if (input.grouped === true) {
      return input;
    }
  var result=[];
  var temp = [];
  for (var i = 0 ; i < input.length ; i++) {
      temp.push(input[i]);
      if (i % size === 2) {
          result.push(temp);
          temp = [];
      }
  }
  if (temp.length > 0) {
      result.push(temp);
  }
  angular.copy(result, input);
  input.grouped = true;
  return input;
}; 
}).

Обратите внимание на использование маркера angular.copy и .grouped на входе, но безрезультатно:( Я знаю, например, "10 $digest() итераций.! Aborting" из-за фильтра, использующего angularjs, но, очевидно, я его не понял.

Более того, я думаю, что логика группировки немного наивна, но эта другая история. Любая помощь будет с благодарностью, так как это сводит меня с ума.

4b9b3361

Ответ 1

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

На самом деле нет причин добавлять "сгруппированную == истинную" проверку там, потому что у вас должен быть полный контроль над вашими собственными фильтрами. Но если это необходимо для вашего приложения, то вы хотите добавить "grouped == true" к результату вашего фильтра, а не к входу.

Как работают фильтры, они меняют ввод и возвращают что-то другое, затем следующий фильтр обрабатывает результат предыдущих фильтров... поэтому ваша "фильтрованная" проверка будет в основном невосприимчивой item in items | filter1 | filter2 | filter3, где filter1 фильтрует элементы, фильтры filter2 результат filter1 и filter3 фильтрует результат фильтра 2... если это имеет смысл.

Вот что я просто взбивал. Я не уверен (пока), если он работает, но он дает вам основную идею. Вы возьмете массив с одной стороны, и вы выплюнете массив массивов на другом.

app.filter('group', function(){
   return function(items, groupSize) {
      var groups = [],
         inner;
      for(var i = 0; i < items.length; i++) {
         if(i % groupSize === 0) {
            inner = [];
            groups.push(inner);
         }
         inner.push(items[i]);
      }
      return groups;
   };
});

HTML

<ul ng-repeat="grouping in items | group:3">
    <li ng-repeat="item in grouping">{{item}}</li>
</ul>

ИЗМЕНИТЬ

Возможно, было бы лучше увидеть все эти фильтры в вашем коде, но похоже, что это вызывает проблемы, потому что его постоянно нужно переоценивать на $digest. Поэтому я предлагаю вам сделать что-то вроде этого:

app.controller('MyCtrl', function($scope, $filter) {
   $scope.blueprints = [ /* your data */ ];
   $scope.currentPage = 0;
   $scope.pageSize = 30;
   $scope.groupSize = 3;
   $scope.sortPty = 'stuff';

   //load our filters
   var orderBy = $filter('orderBy'),
       startFrom = $filter('startFrom'),
       limitTo = $filter('limitTo'),
       group = $filter('group'); //from the filter above

   //a method to apply the filters.
   function updateBlueprintDisplay(blueprints) {
        var result = orderBy(blueprints, $scope.sortPty);
        result = startForm(result, $scope.currentPage * $scope.pageSize);
        result = limitTo(result, $scope.pageSize);
        result = group(result, 3);
        $scope.blueprintDisplay = result;
   }

   //apply them to the initial value.
   updateBlueprintDisplay();

   //watch for changes.
   $scope.$watch('blueprints', updateBlueprintDisplay);
});

затем в вашей разметке:

<ul ng-repeat="grouping in blueprintDisplay">
   <li ng-repeat="item in grouping">{{item}}</li>
</ul>

... Я уверен, что там есть опечатки, но это основная идея.


ИЗМЕНИТЬ СНОВА: Я знаю, что вы уже приняли этот ответ, но есть еще один способ сделать это, я недавно узнал, что вам может понравиться лучше:

<div ng-repeat="item in groupedItems = (items | group:3 | filter1 | filter2)">
    <div ng-repeat="subitem in items.subitems">
    {{subitem}}
    </div>
</div>

Это создаст новое свойство в вашей области $под названием $scope.groupedItems "на лету", которое должно эффективно кэшировать ваши отфильтрованные и сгруппированные результаты.

Дайте ему вихрь и сообщите мне, если это сработает для вас. Если нет, я думаю, что другой ответ может быть лучше.

Ответ 2

Несмотря на это, я все еще вижу ошибку $digest, которая вызывает недоумение: plnkr.co/edit/tHm8uYfjn8EJk3cG31DP - blesh 22 января в 17:21

Вот plunker, раздвоенный с исправлением ошибки $digest, используя функцию memsize underscore: http://underscorejs.org/#memoize.

Проблема заключалась в том, что Angular пытается обработать фильтрованную коллекцию как другую коллекцию во время каждой итерации. Чтобы убедиться, что возврат фильтра всегда возвращает те же объекты, используйте memoize.

http://en.wikipedia.org/wiki/Memoization

Еще один пример группировки с подчеркиванием: Angular фильтр работает, но вызывает "10 $переходов итераций, достигнутых"

Ответ 3

Вы можете использовать фильтр groupBy модуля angular.filter, и сделать что-то вроде этого:
использование: (key, value) in collection | groupBy: 'property' или 'propperty.nested'
JS:

$scope.players = [
  {name: 'Gene', team: 'alpha'},
  {name: 'George', team: 'beta'},
  {name: 'Steve', team: 'gamma'},
  {name: 'Paula', team: 'beta'},
  {name: 'Scruath', team: 'gamma'}
];

HTML:

<ul ng-repeat="(key, value) in players | groupBy: 'team'" >
  Group name: {{ key }}
  <li ng-repeat="player in value">
    player: {{ player.name }} 
  </li>
</ul>
<!-- result:
  Group name: alpha
    * player: Gene
  Group name: beta
    * player: George
    * player: Paula
  Group name: gamma
    * player: Steve
    * player: Scruath