Skip to content

Instantly share code, notes, and snippets.

@CharlieGreenman
Last active January 11, 2024 18:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CharlieGreenman/5352cec2424f9f20d11d48a5de27d8ac to your computer and use it in GitHub Desktop.
Save CharlieGreenman/5352cec2424f9f20d11d48a5de27d8ac to your computer and use it in GitHub Desktop.
Track by property for Angular. Useful for cdk-tree to allow it to use immutable data and be performance conscious
// Import the core angular services.
import { Pipe } from "@angular/core";
import { PipeTransform } from "@angular/core";
// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //
interface TrackByFunctionCache {
[ propertyName: string ]: <T>( index: number, item: T ) => any;
}
// Since the resultant TrackBy functions are based purely on a static property names, we
// can cache these Functions across the entire app. No need to generate more than one
// Function for the same property names.
const cache: TrackByFunctionCache = Object.create( null );
@Pipe({
name: "trackByProperty",
pure: true
})
export class TrackByPropertyPipe implements PipeTransform {
// I return a TrackBy function that plucks the given properties from the ngFor item.
transform( propertyNames: "$index");
transform( propertyNames: string);
transform( propertyNames: string[]);
transform( propertyNames: any) {
let cacheKey = propertyNames;
// If the given property names are defined as an Array, then we have to generate
// the item identity based on the composition of several item values (in which
// each key in the input maps to a property on the item).
if ( Array.isArray( propertyNames ) ) {
cacheKey = propertyNames.join( "->" );
// Ensure cached identity function.
if (!cache[cacheKey]) {
cache[ cacheKey ] = function trackByProperty<T>( index: number, item: T ) : any {
const values = [] as any;
// Collect the item values that will be aggregated in the resultant
// item identity
for (const propertyName of propertyNames ) {
values.push((item[propertyName]));
}
return( values.join( "->" ) );
};
}
// If the property name is the special "$index" key, we'll create an identity
// function that simply uses the collection index. This assumes that the order of
// the collection is stable across change-detection cycles.
} else if ( propertyNames === "$index" ) {
// Ensure cached identity function.
if ( ! cache[ cacheKey ] ) {
cache[ cacheKey ] = function trackByProperty<T>( index: number, item: T ) : any {
return( index ); // <---- Using INDEX.
};
}
// By default, we'll use the provided item property value as the identity.
} else {
// Ensure cached identity function.
if ( ! cache[ cacheKey ] ) {
cache[ cacheKey ] = function trackByProperty<T>( index: number, item: T ) : any {
return( item[ propertyNames ] ); // <---- Using VALUE.
};
}
}
return( cache[ cacheKey ] );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment