Today I Learned

TIL, 2022-01-16, Pipes

Weekend Reading about Pipes

Experiment: Injecting A Component Reference Into A Pipe Instance In Angular 6.0.0

Reference

  • DI token that would explicitly provide the Component to the FnPipe.
// I provide a dependency-injection token for the Fn pipe execution context.
export class FnPipeContext {
  // ...
}

@Pipe({
name: "fn",
pure: true
})
export class FnPipe implements PipeTransform {

  private context: any;

  // I initialize the fn-pipe.
  // --
  // NOTE: We are injecting an OPTIONAL context for function execution.
  constructor( @Optional() @Self() context: FnPipeContext ) {

    this.context = context || null;

  }

  // ---
  // PUBLIC METHODS.
  // ---

  // I pass the first and rest arguments to the given function reference. This pipe
  // is designed to be used in a template to access a component method:
  // --
  // In a template: 
  // --
  // ... becomes the invocation: context.componentMethodRef( valueA, valueB ).
  public transform(
      headArgument: any,
      fnReference: Function,
      ...tailArguments: any[]
      ) : any {

    // Due to the way pipes receive arguments, we can have inputs on both sides of
    // the function reference. As such, let's join the two input sets when invoking
    // the given Function reference.
    return( fnReference.apply( this.context, [ headArgument, ...tailArguments ] ) );

  }

}
  • Getting the component reference - can be done with { provide: FnPipeContext, useClass: AppComponent }
  • View provider is telling the component’s local injector to use an instance of AppComponent as the injectable value for FnPipeContext.
  • You can inject an instance of ChangeDetectorRef and it has ViewRef which contains a property “context” which is the instance of the component in which the pipe is being used.
  • This would allow you to bind to the component instance without any special providers being set up. On the downside it’s a bit hacky because the ChangeDetectorRef type itself does not have the “context” property.
  • Reference
    • An impure Pipe can have unique state for every instance of the Pipe, whereas a pure Pipe can only have unique state for every parent context.
  • Provider vs ViewProvider Reference
    • You’d really just use this if there was content projected - this limits the provider to children other than projected content, while providers allows all children to use the provider.
    • If we want to have one instance of a service per component, and shared with all the component’s children, we configure it on the providers property on our component decorator. Child is a view children.
    • If we want to have one instance of a service per component, and shared with only the component’s view children and not the component’s content children, we configure it on the viewProviders property of our component decorator.
  • Generic pipe: Reference
  • A collection of pipes: Reference
  • Filtering pipe: Reference

I like this API:

transform(array: any[], filter: any): any {
  if (!array) {
    return array;
  }

  switch (typeof filter) {
    case 'boolean':
      return array.filter(this.filterByBoolean(filter));
    case 'string':
      if (FilterPipe.isNumber(filter)) {
        return array.filter(this.filterDefault(filter));
      }
      return array.filter(this.filterByString(filter));
    case 'object':
      return array.filter(this.filterByObject(filter));
    case 'function':
      return array.filter(filter);
  }
  return array.filter(this.filterDefault(filter));

This project is maintained by daryllxd