fix(differ): clean up stale identity change refs

Closes #7193
This commit is contained in:
Kara Erickson 2016-02-24 08:40:02 -08:00 committed by vsavkin
parent 8bb66a5eb3
commit ab36ea097b
3 changed files with 51 additions and 5 deletions

View File

@ -325,6 +325,9 @@ export class DefaultIterableDiffer implements IterableDiffer {
if (this._removalsTail !== null) {
this._removalsTail._nextRemoved = null;
}
if (this._identityChangesTail !== null) {
this._identityChangesTail._nextIdentityChange = null;
}
}
/** @internal */

View File

@ -365,7 +365,7 @@ export function main() {
it('should not replace tracked items',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<template ngFor #item [ngForOf]="items" [ngForTrackBy]="customTrackBy" #i="index">
`<template ngFor #item [ngForOf]="items" [ngForTrackBy]="trackById" #i="index">
<p>{{items[i]}}</p>
</template>`;
tcb.overrideTemplate(TestComponent, template)
@ -387,7 +387,7 @@ export function main() {
it('should update implicit local variable on view',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<div><template ngFor #item [ngForOf]="items" [ngForTrackBy]="customTrackBy">{{item['color']}}</template></div>`;
`<div><template ngFor #item [ngForOf]="items" [ngForTrackBy]="trackById">{{item['color']}}</template></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
@ -403,7 +403,7 @@ export function main() {
it('should move items around and keep them updated ',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<div><template ngFor #item [ngForOf]="items" [ngForTrackBy]="customTrackBy">{{item['color']}}</template></div>`;
`<div><template ngFor #item [ngForOf]="items" [ngForTrackBy]="trackById">{{item['color']}}</template></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
@ -418,6 +418,24 @@ export function main() {
async.done();
});
}));
it('should handle added and removed items properly when tracking by index',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<div><template ngFor #item [ngForOf]="items" [ngForTrackBy]="trackByIndex">{{item}}</template></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.items = ['a', 'b', 'c', 'd'];
fixture.detectChanges();
fixture.debugElement.componentInstance.items = ['e', 'f', 'g', 'h'];
fixture.detectChanges();
fixture.debugElement.componentInstance.items = ['e', 'f', 'h'];
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('efh');
async.done();
});
}));
});
});
}
@ -432,7 +450,8 @@ class TestComponent {
@ContentChild(TemplateRef) contentTpl: TemplateRef;
items: any;
constructor() { this.items = [1, 2]; }
customTrackBy(index: number, item: any): string { return item['id']; }
trackById(index: number, item: any): string { return item['id']; }
trackByIndex(index: number, item: any): number { return index; }
}
@Component({selector: 'outer-cmp'})

View File

@ -338,7 +338,7 @@ export function main() {
});
});
describe('trackBy function', function() {
describe('trackBy function by id', function() {
var differ;
var trackByItemId = (index: number, item: any): any => item.id;
@ -433,5 +433,29 @@ export function main() {
}));
});
});
describe('trackBy function by index', function() {
var differ;
var trackByIndex = (index: number, item: any): number => index;
beforeEach(() => { differ = new DefaultIterableDiffer(trackByIndex); });
it('should track removals normally', () => {
differ.check(['a', 'b', 'c', 'd']);
differ.check(['e', 'f', 'g', 'h']);
differ.check(['e', 'f', 'h']);
expect(differ.toString())
.toEqual(iterableChangesAsString({
collection: ['e', 'f', 'h'],
previous: ['e', 'f', 'h', 'h[3->null]'],
removals: ['h[3->null]'],
identityChanges: ['h']
}));
});
});
});
}