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 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
@ -91,13 +92,17 @@ export class KeyValuePipe implements PipeTransform {
}
const differChanges: KeyValueChanges<K, V>|null = this.differ.diff(input as any);
const compareFnChanged = compareFn !== this.compareFn;
if (differChanges) {
this.keyValues = [];
differChanges.forEachItem((r: KeyValueChangeRecord<K, V>) => {
this.keyValues.push(makeKeyValuePair(r.key, r.currentValue!));
});
}
if (differChanges || compareFnChanged) {
this.keyValues.sort(compareFn);
this.compareFn = compareFn;
}
return this.keyValues;
}

View File

@ -51,6 +51,15 @@ describe('KeyValuePipe', () => {
{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', () => {
const pipe = new KeyValuePipe(defaultKeyValueDiffers);
const transform1 = pipe.transform({1: 2});
@ -114,6 +123,15 @@ describe('KeyValuePipe', () => {
{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', () => {
const pipe = new KeyValuePipe(defaultKeyValueDiffers);
const transform1 = pipe.transform(new Map([[1, 2]]));