Created
July 21, 2021 16:03
-
-
Save brokenthorn/881507cb59c8cb7854d637c865fd376c to your computer and use it in GitHub Desktop.
Angular Pipe Snippet for Recursive Filter Object Properties By Term with optional limit to a single property
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Injectable, Pipe, PipeTransform} from '@angular/core'; | |
@Pipe({ | |
name: 'filterBy', | |
pure: true | |
}) | |
@Injectable() | |
export class FilterByPipe implements PipeTransform { | |
/** | |
* An array filter function. | |
* | |
* If `item` is a string, this function returns true if it includes the search term `term`. | |
* | |
* If `item` is an object, this function is called recursively to traverse that object until it finds a string | |
* property that contains the search term `term` and it returns true in that case, otherwise it returns false. | |
* | |
* If `onlyProperty` is given and `item` has that property, this function either only traverses that property of | |
* `item` if `item[onlyProperty]` is an object, or only checks if `term` is included in that property if it is a | |
* string. | |
* | |
* If `onlyProperty` is given and `item` does not contain that property, this function returns false immediately. | |
* | |
* @param item The input item to traverse and check if it includes `term`. | |
* @param term The search term. | |
* @param onlyProperty An optional single property of `item` to traverse and check if it includes `term`. | |
* @param caseSensitive If set to true, will perform case-sensitive comparisons. | |
*/ | |
static filter(item: any, | |
term: string, | |
caseSensitive: boolean = false, | |
onlyProperty: string | null = null): boolean { | |
if (term === null || term.length === 0) { | |
return true; | |
} | |
// FIXME: with very large objects, each recursion of this function will allocate a new instance of this variable. | |
const searchTerm = caseSensitive ? term : term.toLowerCase(); | |
if (typeof item === 'string') { | |
const itemAsString = caseSensitive ? item as string : (item as string).toLowerCase(); | |
return itemAsString.includes(searchTerm); | |
} | |
if (typeof item === 'object') { | |
// short-circuit: if onlyProperty is given, return the result of a recursive call that only goes down the tree | |
// starting at the object at item[onlyProperty]: | |
if (onlyProperty !== null && onlyProperty.length > 0) { | |
if (!item.hasOwnProperty(onlyProperty)) { | |
return false; | |
} | |
const propertyValue = item[onlyProperty]; | |
return FilterByPipe.filter(propertyValue, searchTerm, caseSensitive); | |
} | |
for (const propertyName in item) { | |
if (item.hasOwnProperty(propertyName)) { | |
const propertyValue = item[propertyName]; | |
if (propertyValue === null || propertyValue === undefined) { | |
continue; | |
} | |
if (FilterByPipe.filter(propertyValue, searchTerm, caseSensitive)) { | |
return true; | |
} | |
} | |
} | |
} | |
return false; | |
} | |
// TODO: Add support for string[] or maybe even number[] input items | |
transform(items: Array<{ [key: string]: any }>, | |
searchTerm: string, | |
caseSensitive: boolean = false, | |
property: string | null = null): Array<{ [key: string]: any }> { | |
if (!items || !searchTerm) { | |
return items; | |
} | |
return items.filter(item => FilterByPipe.filter(item, searchTerm, caseSensitive, property)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Used like so: