Ответ 1
По сравнению с AngularJS 1.2: Выражение "track by" было добавлено в ng-repeat и более правильно решает эту проблему, как показано в следующем коде.
<h1 ng-repeat="item in func() track by $index">something</h1> $scope.func = function(){ return [{"property" : "value1"},{"property": "value2"}]; }
Следующая статья помогает понять выражение более подробно и почему это так полезно, особенно при работе с $$ haskey Использование Track-By с ngRepeat In AngularJS 1.2 от Ben Nadal.
Проблема в том, что вы каждый раз создаете новый массив, поэтому нужно что-то новое, чтобы angular отслеживать. Насколько я могу судить, ng-repeat
запускается, а затем снова проверяет свою коллекцию, чтобы увидеть, что-либо изменилось в этом цикле. Поскольку функция возвращает новый массив, который воспринимается как изменение.
Проверьте это: http://jsfiddle.net/kL5YZ/.
Если вы посмотрите в console.log
и нажмите кнопку, вы увидите, что свойство $$hashKey
объектов изменяется каждый раз, когда выполняется ng-repeat.
Изменение происходит начиная с версии 1.1.4, но журнал изменений не дает никаких указаний относительно того, почему поведение отличается. Новое поведение имеет для меня больше смысла.
Вот отличный пост, который я нашел, объясняя текущее поведение в глубину: Как петля через элементы, возвращаемые функцией с помощью ng-repeat?
Если вы каждый раз возвращаете один и тот же объект/массив, у вас не будет ошибки. Вы можете иметь кеш функции, который он создает на основе аргументов, и всегда возвращать тот же массив/объект, когда эти аргументы передаются. Таким образом, myFunc ('foo') всегда будет возвращать тот же массив, а не новый, который выглядит одна и та же. См. Примечания в моем коде ниже. Живая демонстрация (нажмите).
<div ng-repeat="foo in foos">
<div ng-repeat="bar in barFunc(foo)">{{bar.text}}</div>
<div ng-repeat="bar in barFunc('test')">{{bar.text}}</div>
</div>
JavaScript:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, myService) {
$scope.foos = [
'a','b','c'
];
//I put this into a service to avoid cluttering the controller
$scope.barFunc = myService.getObj;
});
app.factory('myService', function() {
/*
* anything created will be stored in this cache object,
* based on the arguments passed to `getObj`.
* If you need multiple arguments, you could form them into a string,
* and use that as the cache key
* since there only one argument here, I'll just use that
*/
var cache = {};
var myService = {
getObj : function(val) {
//if we haven't created an array with this argument before
if (!cache[val]) {
//create one and store it in the cache with that argument as the key
cache[val] = [
{text:val}
];
}
//return the cached array
return cache[val];
}
};
return myService;
});