Merge pull request #4789 from tsiegleauq/user-list-sort

Fix sorting with empty strings
This commit is contained in:
Emanuel Schütze 2019-06-27 15:21:38 +02:00 committed by GitHub
commit b7d35d1fa1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 60 additions and 48 deletions

View File

@ -211,6 +211,14 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
return data.sort(this.sortFn); return data.sort(this.sortFn);
} }
/**
* Helper function to determine false-like values (if they are not boolean)
* @param property
*/
private isFalsy(property: any): boolean {
return property === null || property === undefined || property === 0 || property === '';
}
/** /**
* Recreates the sorting function. Is supposed to be called on init and * Recreates the sorting function. Is supposed to be called on init and
* every time the sorting (property, ascending/descending) or the language changes * every time the sorting (property, ascending/descending) or the language changes
@ -218,59 +226,63 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
protected updateSortedData(): void { protected updateSortedData(): void {
if (this.inputData) { if (this.inputData) {
const property = this.sortProperty as string; const property = this.sortProperty as string;
const intl = new Intl.Collator(this.translate.currentLang);
this.outputSubject.next( const intl = new Intl.Collator(this.translate.currentLang, {
this.inputData.sort((itemA, itemB) => { numeric: true,
const firstProperty = this.ascending ? itemA[property] : itemB[property]; ignorePunctuation: true,
const secondProperty = this.ascending ? itemB[property] : itemA[property]; sensitivity: 'base'
if (typeof firstProperty !== typeof secondProperty) { });
// undefined/null items should always land at the end
if (!firstProperty) { this.inputData.sort((itemA, itemB) => {
return 1; // always sort falsy values to the bottom
} else if (!secondProperty) { if (this.isFalsy(itemA[property]) && this.isFalsy(itemB[property])) {
return 0;
} else if (this.isFalsy(itemA[property])) {
return 1;
} else if (this.isFalsy(itemB[property])) {
return -1;
}
const firstProperty = this.ascending ? itemA[property] : itemB[property];
const secondProperty = this.ascending ? itemB[property] : itemA[property];
switch (typeof firstProperty) {
case 'boolean':
if (!firstProperty && secondProperty) {
return -1; return -1;
} else { } else {
throw new TypeError('sorting of items failed because of mismatched types');
}
} else {
if (
(firstProperty === null || firstProperty === undefined) &&
(secondProperty === null || secondProperty === undefined)
) {
return 1; return 1;
} }
switch (typeof firstProperty) { case 'number':
case 'boolean': return firstProperty > secondProperty ? 1 : -1;
if (firstProperty === false && secondProperty === true) { case 'string':
return -1; if (!!firstProperty && !secondProperty) {
} else { return -1;
return 1; } else if (!firstProperty && !!secondProperty) {
} return 1;
case 'number': } else if ((!secondProperty && !secondProperty) || firstProperty === secondProperty) {
return firstProperty > secondProperty ? 1 : -1; return 0;
case 'string': } else {
if (!firstProperty) { return intl.compare(firstProperty, secondProperty);
return 1;
}
return intl.compare(firstProperty, secondProperty);
case 'function':
const a = firstProperty();
const b = secondProperty();
return intl.compare(a, b);
case 'object':
if (firstProperty instanceof Date) {
return firstProperty > secondProperty ? 1 : -1;
} else {
return intl.compare(firstProperty.toString(), secondProperty.toString());
}
case 'undefined':
return 1;
default:
return -1;
} }
} case 'function':
}) const a = firstProperty();
); const b = secondProperty();
return intl.compare(a, b);
case 'object':
if (firstProperty instanceof Date) {
return firstProperty > secondProperty ? 1 : -1;
} else {
return intl.compare(firstProperty.toString(), secondProperty.toString());
}
case 'undefined':
return 1;
default:
return -1;
}
});
this.outputSubject.next(this.inputData);
} }
} }
} }