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

Бесконечная сигнальная петля в фильтре 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 является булевым.

4b9b3361

Ответ 1

Я написал этот настраиваемый фильтр для 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 map или underscorejs map, например.

Ответ 2

Это происходит, когда вы манипулируете возвращенным массивом так, чтобы он не соответствовал исходному массиву. См. Например:

.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++;
}

Ответ 3

output[count] = {};

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

Чтобы избежать проблемы, в основном вам необходимо убедиться, что каждый элемент в модели остается "тем же", то есть

firstCallOutput[0] == secondCallOutput[0]
&& firstCallOutput[1] == secondCallOutput[1]
&& firstCallOutput[2] == secondCallOutput[2]
...

Это равенство должно поддерживаться до тех пор, пока вы не измените модель, поэтому ng-repeat не будет ошибочно думать, что модель была изменена.

Обратите внимание, что два новых экземпляра не равны, т.е. {} != {}