fix(common): re-sort output of `KeyValuePipe` when `compareFn` changes (#42821)

Previously, if only the `compareFn` changed but the data itself did not, then
the `KeyValuePipe` did not re-sort the output.

Fixes #42819

PR Close #42821
This commit is contained in:
Meir Blumenfeld 2021-07-12 12:44:07 -04:00 committed by Andrew Kushnir
parent 81dce5c664
commit e42aa6c13b
2 changed files with 23 additions and 0 deletions

View File

@ -49,6 +49,7 @@ export class KeyValuePipe implements PipeTransform {
private differ!: KeyValueDiffer<any, any>; private differ!: KeyValueDiffer<any, any>;
private keyValues: Array<KeyValue<any, any>> = []; private keyValues: Array<KeyValue<any, any>> = [];
private compareFn: (a: KeyValue<any, any>, b: KeyValue<any, any>) => number = defaultComparator;
/* /*
* NOTE: when the `input` value is a simple Record<K, V> object, the keys are extracted with * NOTE: when the `input` value is a simple Record<K, V> object, the keys are extracted with
@ -91,13 +92,17 @@ export class KeyValuePipe implements PipeTransform {
} }
const differChanges: KeyValueChanges<K, V>|null = this.differ.diff(input as any); const differChanges: KeyValueChanges<K, V>|null = this.differ.diff(input as any);
const compareFnChanged = compareFn !== this.compareFn;
if (differChanges) { if (differChanges) {
this.keyValues = []; this.keyValues = [];
differChanges.forEachItem((r: KeyValueChangeRecord<K, V>) => { differChanges.forEachItem((r: KeyValueChangeRecord<K, V>) => {
this.keyValues.push(makeKeyValuePair(r.key, r.currentValue!)); this.keyValues.push(makeKeyValuePair(r.key, r.currentValue!));
}); });
}
if (differChanges || compareFnChanged) {
this.keyValues.sort(compareFn); this.keyValues.sort(compareFn);
this.compareFn = compareFn;
} }
return this.keyValues; return this.keyValues;
} }

View File

@ -51,6 +51,15 @@ describe('KeyValuePipe', () => {
{key: 'a', value: 1}, {key: 'b', value: 1} {key: 'a', value: 1}, {key: 'b', value: 1}
]); ]);
}); });
it('should reorder when compareFn changes', () => {
const pipe = new KeyValuePipe(defaultKeyValueDiffers);
const input = {'b': 1, 'a': 2};
pipe.transform<string, number>(input);
expect(pipe.transform<string, number>(input, (a, b) => a.value - b.value)).toEqual([
{key: 'b', value: 1},
{key: 'a', value: 2},
]);
});
it('should return the same ref if nothing changes', () => { it('should return the same ref if nothing changes', () => {
const pipe = new KeyValuePipe(defaultKeyValueDiffers); const pipe = new KeyValuePipe(defaultKeyValueDiffers);
const transform1 = pipe.transform({1: 2}); const transform1 = pipe.transform({1: 2});
@ -114,6 +123,15 @@ describe('KeyValuePipe', () => {
{key: {id: 1}, value: 1}, {key: {id: 1}, value: 1},
]); ]);
}); });
it('should reorder when compareFn changes', () => {
const pipe = new KeyValuePipe(defaultKeyValueDiffers);
const input = new Map([['b', 1], ['a', 2]]);
pipe.transform<string, number>(input);
expect(pipe.transform<string, number>(input, (a, b) => a.value - b.value)).toEqual([
{key: 'b', value: 1},
{key: 'a', value: 2},
]);
});
it('should return the same ref if nothing changes', () => { it('should return the same ref if nothing changes', () => {
const pipe = new KeyValuePipe(defaultKeyValueDiffers); const pipe = new KeyValuePipe(defaultKeyValueDiffers);
const transform1 = pipe.transform(new Map([[1, 2]])); const transform1 = pipe.transform(new Map([[1, 2]]));