Бесконечный цикл дайджеста в фильтре AngularJS
Я написал этот пользовательский фильтр для AngularJS, но когда он запускается, я получаю бесконечную ошибку цикла дайджеста. Почему это происходит и как я могу это исправить?
angular.module("app", []).
filter('department', function(filterFilter) {
return function(items, args) {
var productMatches;
var output = [];
var count = 0;
if (args.selectedDepartment.Id !== undefined && args.option) {
for (let i = 0; i < items.length; i++) {
productMatches = items[i].products.filter(function(el) {
return el.Order__r.Department__r.Id === args.selectedDepartment.Id;
});
if (productMatches.length !== 0) {
output[count] = {};
output[count].products = productMatches;
output[count].firstProduct = items[i].firstProduct;
count++;
}
}
}
return output;
};
}).
Это соответствующий HTML:
<tr class='destination' ng-repeat-start='pickupAccount in pickupAccounts | department : {"selectedDepartment": selectedDepartment, "option": displayExclusive }'>
<!-- td here -->
</tr>
displayExclusive
является логическим.
3 ответа:
Я написал этот пользовательский фильтр для AngularJS, но когда он запускается, я получаю бесконечную ошибку цикла дайджеста.
Имейте в виду, что фильтр должен возвращать массив той же структуры объекта. Когда мы активируем фильтр, он запускает цикл дайджеста, который снова будет работать над нашим фильтром. Если что - то изменилось в списке вывода-запускает новый цикл дайджеста и так далее. после 10 попыток он бросит нам
Infinite Digest Loop
исключение
Тестирование
Этот пустой фильтр будет работать (100%). На самом деле мы здесь ничего не делаем, а возвращаем тот же самый объект, который получает фильтр.
filter('department', function(filterFilter) { return function(items, args) { var output = items; return output; }; })
Теперь основная идея такова: напишите некоторое условие, чтобы подтолкнуть к
output
объектам из входного списка a. e.items
на основе некоторогоif
оператора, a. e.var output = []; if (args.selectedDepartment.Id !== undefined && args.option) { angular.forEach(items, function(item) { if(<SOME CONDITION>) { output.push(item); } }); }
Таким образом, это тоже будет работать.
Наш случай:
У нас есть такая логика:
productMatches = items[i].products.filter(function(el) { return el.Order__r.Department__r.Id === args.selectedDepartment.Id; }); if (productMatches.length !== 0) { output[count] = {}; output[count].products = productMatches; output[count].firstProduct = items[i].firstProduct; count++; }
Здесь мы полностью модифицировали объект, который был сохранен в
output
. Так что в следующем цикле дайджеста нашitems
снова изменится и снова.
Заключение
Основная цель
Вышеупомянутая логика, которую вы написали, связана с манипуляцией данными,а не с фильтром. Фильтрfilter
- фильтровать список, а не изменять содержимое объекта списка.department
возвращает одинаковую длину элементов.Для достижения своей цели вы можете использовать карту lodash или карту underscorejs, например.
Это происходит, когда вы манипулируете возвращаемым массивом таким образом, что он не соответствует исходному массиву. См., например:
.filter("department", function() { return function(items, args) { var output = []; for (var i = 0; i < items.length; i++) { output[i] = {}; output[i] = items[i]; // if you don't do this, the next filter will fail output[i].product = items[i]; } return output; } }
Вы можете увидеть, как это происходит в следующем упрощенном jsfiddle: https://jsfiddle.net/u873kevp/1/
Если возвращаемый массив имеет ту же "структуру", что и входной массив, это вызовет эти ошибки.
Это должно работать в вашем случае, просто назначив исходный элемент возвращаемому элементу:
if (productMatches.length !== 0) { output[count] = items[i]; // do this output[count].products = productMatches; output[count].firstProduct = items[i].firstProduct; count++; }
output[count] = {};
Выше строка является основной проблемой. Вы создаете новый экземпляр, и
ng-repeat
обнаружит, что модель постоянно изменяется бесконечно. (в то время как вы думаете, что ничего не меняется с точки зрения пользовательского интерфейса)Чтобы избежать этой проблемы, в основном вам нужно убедиться, что каждый элемент в модели остается "тем же самым", т. е.
Это равенство должно сохраняться до тех пор, пока вы не измените модель, таким образом,firstCallOutput[0] == secondCallOutput[0] && firstCallOutput[1] == secondCallOutput[1] && firstCallOutput[2] == secondCallOutput[2] ...
ng-repeat
не будет "ошибочно" думать, что модель имеет все изменилось. Обратите внимание, что два новых экземпляра не равны, т. е.{} != {}