diff --git a/packages/core/src/change_detection/differs/default_keyvalue_differ.ts b/packages/core/src/change_detection/differs/default_keyvalue_differ.ts index fd3165c5dd..ebff2285d8 100644 --- a/packages/core/src/change_detection/differs/default_keyvalue_differ.ts +++ b/packages/core/src/change_detection/differs/default_keyvalue_differ.ts @@ -120,7 +120,6 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer, KeyVal } this._removalsHead = insertBefore; - this._removalsTail = insertBefore; for (let record = insertBefore; record !== null; record = record._nextRemoved) { if (record === this._mapHead) { @@ -135,6 +134,10 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer, KeyVal } } + // Make sure tails have no next records from previous runs + if (this._changesTail) this._changesTail._nextChanged = null; + if (this._additionsTail) this._additionsTail._nextAdded = null; + return this.isDirty; } @@ -222,7 +225,7 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer, KeyVal this._changesHead = this._changesTail = null; this._additionsHead = this._additionsTail = null; - this._removalsHead = this._removalsTail = null; + this._removalsHead = null; } } @@ -254,28 +257,17 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer, KeyVal } toString(): string { - const items: any[] = []; - const previous: any[] = []; - const changes: any[] = []; - const additions: any[] = []; - const removals: any[] = []; - let record: KeyValueChangeRecord_|null; + const items: string[] = []; + const previous: string[] = []; + const changes: string[] = []; + const additions: string[] = []; + const removals: string[] = []; - for (record = this._mapHead; record !== null; record = record._next) { - items.push(stringify(record)); - } - for (record = this._previousMapHead; record !== null; record = record._nextPrevious) { - previous.push(stringify(record)); - } - for (record = this._changesHead; record !== null; record = record._nextChanged) { - changes.push(stringify(record)); - } - for (record = this._additionsHead; record !== null; record = record._nextAdded) { - additions.push(stringify(record)); - } - for (record = this._removalsHead; record !== null; record = record._nextRemoved) { - removals.push(stringify(record)); - } + this.forEachItem(r => items.push(stringify(r))); + this.forEachPreviousItem(r => previous.push(stringify(r))); + this.forEachChangedItem(r => changes.push(stringify(r))); + this.forEachAddedItem(r => additions.push(stringify(r))); + this.forEachRemovedItem(r => removals.push(stringify(r))); return 'map: ' + items.join(', ') + '\n' + 'previous: ' + previous.join(', ') + '\n' + diff --git a/packages/core/test/change_detection/differs/default_keyvalue_differ_spec.ts b/packages/core/test/change_detection/differs/default_keyvalue_differ_spec.ts index 0100426dee..11bd1b5eb5 100644 --- a/packages/core/test/change_detection/differs/default_keyvalue_differ_spec.ts +++ b/packages/core/test/change_detection/differs/default_keyvalue_differ_spec.ts @@ -194,6 +194,19 @@ export function main() { })); }); + // https://github.com/angular/angular/issues/14997 + it('should work regardless key order', () => { + differ.check({a: 1, b: 2}); + differ.check({b: 3, a: 2}); + differ.check({a: 1, b: 2}); + + expect(differ.toString()).toEqual(kvChangesAsString({ + map: ['a[2->1]', 'b[3->2]'], + previous: ['b[3->2]', 'a[2->1]'], + changes: ['a[2->1]', 'b[3->2]'] + })); + }); + it('should when the first item is moved', () => { differ.check({a: 'a', b: 'b'}); differ.check({c: 'c', a: 'a'});