3

Я сделаю это довольно простым. У меня есть:Дизайн шаблона AngularJS для ng-повторения по массиву массивов

<div ng-repeat="group in topLevelGroups"> 

    .... 

    <div ng-repeat="item in group.items | filter:itemFilter"> 

     .... 

    </div> 

</div> 

Это работает все хорошо и прекрасно, но я хочу показать где-то общего количества фильтров приводит во всех «группе» с.

Для достижения этой цели, я переместил фильтр в контроллер, например, так:

<div ng-repeat="item in filterItems(group)"> 

// in controller: 

$scope.filterItems = function(group) { 
    var ret = $filter('filter')(g.items, $scope.query); 
    g.filteredItemCount = ret.length 
    return ret 
}; 

$scope.getTotalFiltered = function() { 
    return $scope.data.reduce(function (prev,cur) { 
     return prev + cur.filteredItemCount 
    }, 0) 
} 

Так, по существу, контрейлерный свойство «filteredPostLength» на к группе, когда происходит фильтр, и использовать чтобы суммировать это свойство по всем группам, чтобы получить итоговые отфильтрованные результаты.

Here is a jsFiddle

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

Любой вход очень ценится, спасибо!

ответ

6

Ваш код будет работать, но это не является оптимальным.

Я раздвоенный код jsFiddle и добавил вход для демонстрации его:

  • Открыть http://jsfiddle.net/jvandemo/tDhgv/1/
  • Откройте консоль в вашем браузере
  • Тип что-то в полях ввода, и вы заметите, что filterItems работает 9 раз при каждом изменении $scope.query

Так почему же это?

Ну, есть 2 причины:

  1. Ваш вызов функции внутри нг-повтора, так что вызывается несколько раз (как и ожидалось, никаких сюрпризов здесь)
  2. Там не проблема с вашим filterItems способ.

    Вы назначили метод filterItems внутреннему ng-repeat. Поэтому Angular автоматически будет наблюдать за результатом функции для вас и «обновлять», когда она изменится.

    Тем не менее, в вашем filterItems кодах вы немедленно вносите изменения в данные. Угловой наблюдает за вами, выполняя g.filteredItemCount = ret.length, вызывая Угловое выполнение другого «обновления», так как он обнаруживает новое изменение.

    Если вы должны были прокомментировать этот сингл кода, вы сразу увидите падение количества раз, когда будет запущен метод.

Так что же лучше?

В вашем случае я бы:

  • Define Бодрствующий для $scope.query
  • Фильтра данных в вашем сторожа и хранить его отдельно (оставить исходные данные нетронутыми)
  • Loop отфильтрованных данных с ng-repeat теги:

Ваш код будет более чистым, быстрым и эффективным, что важно, если ваш набор данных будет много би gger.

Я создал jsFiddle для вашего удобства: http://jsfiddle.net/jvandemo/VeLEJ/1/

Если вы откроете консоль, вы увидите, что код работает только один раз, когда $scope.query изменения вместо 9 раз.

Визуально результат будет тот же, но за кулисами есть довольно разница ...

Надежда, что помогает!


ОБНОВЛЕНИЕ:

Подход для повышения производительности является реструктуризация данных (сразу же после загрузки данных).

Я создал jsFiddle с примерами кода для демонстрации его: http://jsfiddle.net/jvandemo/fTE5R/1/

Данные перестраивается, чтобы избежать forEach циклов и избежать многих циклов, как это возможно, и позволить query объект, который будет применяться непосредственно к элементам в директиве.

Это очень похоже на исходный код, но без необходимости вызывать функции фильтрации внутри scope.

Если ваше приложение может доставлять данные в формате $scope.items, весь процесс будет даже быстрее, и шаг оптимизации может быть пропущен.

Надеюсь, что это поможет!

+1

Большое спасибо за объяснение, почему мой метод был намного более неэффективным!Иногда трудно точно знать, как работает Angular. – cemulate

+0

На самом деле, теперь, когда я воплотил это в жизнь, моя работа стала намного хуже. Я думаю, что это из-за того, что я копирую весь набор данных каждый раз при нажатии клавиши (мой набор данных большой, и каждый «элемент» имеет много свойств). Любые предложения по управлению огромным набором данных? – cemulate

+0

Можете ли вы дать оценку размера ваших данных, чтобы я мог имитировать его? Спасибо! – jvandemo

2

, как вы сделали это абсолютно нормально, но есть способ сделать это, не выходя к контроллеру:

Group {{group.id}} (results: {{filtered.length}}) 
<div ng-repeat="item in filtered = (group.items | filter:query)"> 
    {{item.name}} -- {{item.age}} 
</div> 

Вы имеете доступ к фильтрованной переменной «вне» внутренней нг-повтора.

Обновлено jsfiddle: http://jsfiddle.net/thric3blinded/ehQVe/1/

+0

Спасибо за скрипку! Я думаю, что это выглядит намного чище, но как я могу сохранить функциональность суммирования длины отфильтрованных результатов от всех групп? Я мог бы заменить «|» нотация с моей функцией и все еще контрейлерные, что переменная «filterLength»? – cemulate

+0

Я думаю, что для ваших требований решение @ jvandemo имеет гораздо больше смысла. Поскольку ng-repeat автоматически создает копию источника данных, которую вы ему даете, вы не можете получить доступ к фильтру за пределами верхнего уровня ng-repeat (без закрытия). Поэтому управление фильтром в контроллере дает вам максимальную гибкость для копирования/хранения/изменения и управления данными. –

+0

Это не сработало для меня (AJS 1.2.12). Поскольку фильтр возвращал новый экземпляр массива каждый раз, он вызывался каждый раз и приводил к бесконечному циклу дайджеста. –