Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 31c56f5

Browse files
jankucaIgorMinar
authored andcommitted
fix(ngRepeat): correctly track elements even when the collection is initially undefined
Previously if the collection model was set to undefined on the first digest, the repeater would get confused and not use the correct tracking function for associating model with dom elements in the repeater. Closes #4145 Closes #3964
1 parent f8f8f75 commit 31c56f5

File tree

2 files changed

+26
-6
lines changed

2 files changed

+26
-6
lines changed

src/ng/directive/ngRepeat.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
218218
return function($scope, $element, $attr){
219219
var expression = $attr.ngRepeat;
220220
var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
221-
trackByExp, trackByExpGetter, trackByIdFn, trackByIdArrayFn, trackByIdObjFn, lhs, rhs, valueIdentifier, keyIdentifier,
221+
trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
222+
lhs, rhs, valueIdentifier, keyIdentifier,
222223
hashFnLocals = {$id: hashKey};
223224

224225
if (!match) {
@@ -232,7 +233,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
232233

233234
if (trackByExp) {
234235
trackByExpGetter = $parse(trackByExp);
235-
trackByIdFn = function(key, value, index) {
236+
trackByIdExpFn = function(key, value, index) {
236237
// assign key, value, and $index to the locals so that they can be used in hash functions
237238
if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
238239
hashFnLocals[valueIdentifier] = value;
@@ -275,16 +276,17 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
275276
childScope,
276277
key, value, // key/value of iteration
277278
trackById,
279+
trackByIdFn,
278280
collectionKeys,
279281
block, // last object information {scope, element, id}
280282
nextBlockOrder = [];
281283

282284

283285
if (isArrayLike(collection)) {
284286
collectionKeys = collection;
285-
trackByIdFn = trackByIdFn || trackByIdArrayFn;
287+
trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
286288
} else {
287-
trackByIdFn = trackByIdFn || trackByIdObjFn;
289+
trackByIdFn = trackByIdExpFn || trackByIdObjFn;
288290
// if object, extract keys, sort them and use to determine order of iteration over obj props
289291
collectionKeys = [];
290292
for (key in collection) {

test/ng/directive/ngRepeatSpec.js

+20-2
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,26 @@ describe('ngRepeat', function() {
841841
expect(newLis[1]).toEqual(lis[0]);
842842
expect(newLis[2]).toEqual(lis[1]);
843843
});
844+
845+
it('should be stable even if the collection is initially undefined', function () {
846+
scope.items = undefined;
847+
scope.$digest();
848+
849+
scope.items = [
850+
{ name: 'A' },
851+
{ name: 'B' },
852+
{ name: 'C' }
853+
];
854+
scope.$digest();
855+
856+
lis = element.find('li');
857+
scope.items.shift();
858+
scope.$digest();
859+
860+
var newLis = element.find('li');
861+
expect(newLis.length).toBe(2);
862+
expect(newLis[0]).toBe(lis[1]);
863+
});
844864
});
845865

846866
it('should grow multi-node repeater', inject(function($compile, $rootScope) {
@@ -861,8 +881,6 @@ describe('ngRepeat', function() {
861881
$rootScope.$digest();
862882
expect(element.text()).toEqual('T1:D1;T2:D2;T3:D3;');
863883
}));
864-
865-
866884
});
867885

868886
describe('ngRepeat animations', function() {

0 commit comments

Comments
 (0)