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
This commit is contained in:
jankuca 2013-09-24 13:51:28 -07:00 committed by Igor Minar
parent f8f8f754b0
commit 31c56f5400
2 changed files with 26 additions and 6 deletions

View file

@ -218,7 +218,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
return function($scope, $element, $attr){
var expression = $attr.ngRepeat;
var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
trackByExp, trackByExpGetter, trackByIdFn, trackByIdArrayFn, trackByIdObjFn, lhs, rhs, valueIdentifier, keyIdentifier,
trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
lhs, rhs, valueIdentifier, keyIdentifier,
hashFnLocals = {$id: hashKey};
if (!match) {
@ -232,7 +233,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
if (trackByExp) {
trackByExpGetter = $parse(trackByExp);
trackByIdFn = function(key, value, index) {
trackByIdExpFn = function(key, value, index) {
// assign key, value, and $index to the locals so that they can be used in hash functions
if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
hashFnLocals[valueIdentifier] = value;
@ -275,6 +276,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
childScope,
key, value, // key/value of iteration
trackById,
trackByIdFn,
collectionKeys,
block, // last object information {scope, element, id}
nextBlockOrder = [];
@ -282,9 +284,9 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
if (isArrayLike(collection)) {
collectionKeys = collection;
trackByIdFn = trackByIdFn || trackByIdArrayFn;
trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
} else {
trackByIdFn = trackByIdFn || trackByIdObjFn;
trackByIdFn = trackByIdExpFn || trackByIdObjFn;
// if object, extract keys, sort them and use to determine order of iteration over obj props
collectionKeys = [];
for (key in collection) {

View file

@ -841,6 +841,26 @@ describe('ngRepeat', function() {
expect(newLis[1]).toEqual(lis[0]);
expect(newLis[2]).toEqual(lis[1]);
});
it('should be stable even if the collection is initially undefined', function () {
scope.items = undefined;
scope.$digest();
scope.items = [
{ name: 'A' },
{ name: 'B' },
{ name: 'C' }
];
scope.$digest();
lis = element.find('li');
scope.items.shift();
scope.$digest();
var newLis = element.find('li');
expect(newLis.length).toBe(2);
expect(newLis[0]).toBe(lis[1]);
});
});
it('should grow multi-node repeater', inject(function($compile, $rootScope) {
@ -861,8 +881,6 @@ describe('ngRepeat', function() {
$rootScope.$digest();
expect(element.text()).toEqual('T1:D1;T2:D2;T3:D3;');
}));
});
describe('ngRepeat animations', function() {