У меня есть список выбора, в котором содержимое динамически генерируется из содержимого, выбранного в первом списке выбора. Кажется, я не могу найти, почему я получаю эти ошибки при каждом изменении первого списка выбора:
Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [[{"msg":"fn:
regularInterceptedExpression","newVal":42,"oldVal":37},{"msg":"fn: regularInterceptedExpression","newVal":"16","oldVal":"14"}],[{"msg":"fn: regularInterceptedExpression","newVal":47,"oldVal":42},{"msg":"fn: regularInterceptedExpression","newVal":"18","oldVal":"16"}],[{"msg":"fn: regularInterceptedExpression","newVal":52,"oldVal":47},{"msg":"fn: regularInterceptedExpression","newVal":"20","oldVal":"18"}],[{"msg":"fn: regularInterceptedExpression","newVal":57,"oldVal":52},{"msg":"fn: regularInterceptedExpression","newVal":"22","oldVal":"20"}],[{"msg":"fn: regularInterceptedExpression","newVal":62,"oldVal":57},{"msg":"fn: regularInterceptedExpression","newVal":"24","oldVal":"22"}]]
http://errors.angularjs.org/1.4.7/$rootScope/infdig?p0=10&p1=%5B%5B%7B%22ms…Expression%22%2C%22newVal%22%3A%2224%22%2C%22oldVal%22%3A%2222%22%7D%5D%5D
Плюс каждый раз, когда список изменяется, "makeOptions", используемый для создания второго списка, запускается несколько раз за одно изменение списка.
Эти два списка настроены так:
<select ng-model="selected.level1" ng-options="lvl.name as lvl.name for lvl in level1options"></select>
<select ng-model="selected.level2" ng-options="opt.value as opt.label for opt in makeOptions()"></select>
и контроллер:
app.controller('DemoController', function($scope) {
$scope.level1options = [{ name: "A", value: "A" }, { name: "B", value: "B" }, { name: "C", value: "C" }];
$scope.makeOptionsCallCount = 1;
$scope.selected = {};
$scope.makeOptions = function() {
console.log($scope.makeOptionsCallCount++);
var options = [];
for (var i = 0; i < 5; i++) {
options.push({ label: 'Value = ' + i + $scope.selected.level1, value: i + $scope.selected.level1 });
}
return options;
};
});
Вот пример того, что происходит странно:
http://plnkr.co/edit/mKv7nMjot5XqBj4mkvhR?p=preview
Любые идеи, в которых я ошибся?
ОБНОВИТЬ
Возможно, я упростил пример, когда у меня были проблемы. Решение становится более сложным, потому что у меня есть список элементов, где для каждого элемента вы можете выбрать набор значений. Прошу прощения, я забыл этот элемент, задавая свой первоначальный вопрос.
Я создал новый пример, который более точно отражает это:
Когда вы используете внутреннее представление функции, оно выполняется в каждом цикле дайджеста.
Кроме того, угловой добавляет наблюдателя, чтобы вызвать эту функцию, и если вы, например, возвращаете новый массив при каждом вызове - вы идете в бесконечный цикл, потому что [] != []
В вашем случае у вас есть еще одна ошибка: внутри функции, вызываемой в поле зрения, вы меняете переменную, что также показано в поле зрения. Так что для этой переменной также добавлен наблюдатель.
Вы меняете значение в вызове функции, смотрите, как изменилась переменная, снова запустите дайджест, запустите функцию, измените значение, увидите, что переменная изменена и т.д....
Итак, для решения лучше выбрать лучшие варианты сохранения при изменении.
var app = angular.module('demoApp', [])
app.controller('DemoController', function($scope) {
$scope.level1options = [{ name: "A", value: "A" }, { name: "B", value: "B" }, { name: "C", value: "C" }];
$scope.makeOptionsCallCount = 1;
$scope.selected = {};
$scope.makeOptions = function(lvl) {
$scope.options = [];
console.log(++$scope.makeOptionsCallCount);
for (var i = 0; i < 5; i++) {
$scope.options.push({ label: 'Value = ' + i + lvl, value: i + lvl });
}
};
});
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.js"></script>
<div ng-app="demoApp" ng-controller="DemoController">
<div>
<h2>Infinite Digest 2</h2>
<select ng-model="selected.level1" ng-options="lvl.name as lvl.name for lvl in level1options" ng-change="makeOptionsCallCount=0;makeOptions(selected.level1)"></select>
<select ng-model="selected.level2" ng-options="opt.value as opt.label for opt in options"></select>
<br/>
<br/>
<div>Level 1: {{selected.level1}}</div>
<div>Level 2: {{selected.level2}}</div>
<div>makeOptions() Called: {{makeOptionsCallCount}} times</div>
</div>
</div>
ОБНОВИТЬ:
В вашем случае из комментария вы можете воспользоваться тем фактом, что ng-repeat
создает собственную область и сохраняет в нем параметры списка, созданные на событии ng-change.
Кроме того, вы можете даже использовать функцию makeOptions
.
Для ng-change
вы можете передать выражение:
ng-change="optionsLvLs = makeOptions(option.level1)"
здесь, в области ng-repeat
для каждого параметра, в событии изменения будут созданы optionsLvLs
которые не загрязняют ваш объект-вариант, если это имеет значение.
var app = angular.module('demoApp', [])
app.controller('DemoController', function($scope) {
$scope.level1options = [{ name: "A", value: "A" }, { name: "B", value: "B" }, { name: "C", value: "C" }];
$scope.selected = {};
$scope.options = [{ name: "A" }];
$scope.makeOptions = function(level1) {
var options = [];
for (var i = 0; i < 5; i++)
{
options.push({ label: 'Value = ' + i + level1, value: i + level1 });
}
return options;
};
$scope.addQuery = function(idx) {
$scope.options.splice(idx + 1, 0, {});
};
$scope.removeQuery = function (idx) {
$scope.options.splice(idx, 1);
};
});
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.js"></script>
<div ng-controller="DemoController" ng-app="demoApp">
<div>
<h2>Infinite Digest 2</h2>
<div ng-repeat="option in options">
<input type="button" value="+" ng-click="addQuery($index)" />
<input type="button" value="-" ng-click="removeQuery($index)" />
<select ng-model="option.level1" ng-options="lvl.name as lvl.name for lvl in level1options" ng-change="optionsLvLs = makeOptions(option.level1)"></select>
<select ng-model="option.level2" ng-options="opt.value as opt.label for opt in optionsLvLs"></select>
<br/>
<br/>
</div>
</div>
{{ options }}
</div>
Выполняя следующие изменения, для динамического создания данных не требуется вызывать функцию,
$scope.level1options = [{ name: "A", value: "A" }, { name: "B", value: "B" }, { name: "C", value: "C" }];
$scope.level2options = [0,1,2,3,4];
<select ng-model="selected.level1" ng-options="lvl.name as lvl.name for lvl in level1options"></select>
<select ng-model="selected.level2" ng-options="i+selected.level1 as 'Value = '+i+selected.level1 for i in level2options"></select>
Здесь плункер: http://plnkr.co/edit/GQhnjTpB0sLHoiSnchhn?p=preview