// 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. var 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. public transform( propertyNames: "$index" ) : Function; public transform( propertyNames: string ) : Function; public transform( propertyNames: string[] ) : Function; public transform( propertyNames: any ) : Function { console.warn( `Getting track-by for [${ propertyNames.toString() }].` ); var 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 { var values = []; // Collect the item values that will be aggregated in the resultant // item identity for ( var 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 ] ); } }