Angular 5.x中如何动态获取Pipe实例并调用?
Great question! In Angular 5+ (and all subsequent versions), you absolutely can dynamically invoke pipes without needing to inject them directly at compile time—mirroring the behavior you had with AngularJS 1.x's $filter service. Here are two reliable approaches to achieve this:
Approach 1: Using PipeResolver (Dynamic by Pipe Name String)
This method lets you resolve a pipe directly using its string name, just like you did with $filter(filterNameVariable) in AngularJS.
Step-by-Step Implementation
First, import the required Angular core utilities in your component:
import { Component, Injector, PipeResolver } from '@angular/core'; import { PipeTransform } from '@angular/core';Inject
InjectorandPipeResolverinto your component's constructor:constructor( private injector: Injector, private pipeResolver: PipeResolver ) {}Dynamically resolve and invoke the pipe:
ngOnInit() { // Your dynamic pipe name (could come from a variable, API response, etc.) const targetPipeName = 'uppercase'; // Example: Angular's built-in uppercase pipe const valueToTransform = 'hello dynamic pipes!'; const pipeArguments = []; // Add any args your pipe requires // Resolve the pipe class from its name const pipeClass = this.pipeResolver.resolve(targetPipeName); // Get an instance of the pipe using the injector const pipeInstance = this.injector.get(pipeClass) as PipeTransform; // Call the pipe's transform method with your value and args const transformedValue = pipeInstance.transform(valueToTransform, ...pipeArguments); console.log(transformedValue); // Output: HELLO DYNAMIC PIPES! }
Important Notes
- Ensure the pipe you're targeting is declared in your component's module (or imported via a shared module that's added to your module's
importsarray). ThePipeResolvercan only find pipes that are part of the current Angular module context. - This works for both custom pipes (with their defined
namein the@Pipedecorator) and Angular's built-in pipes (likedate,currency, etc.—use their official string names as documented).
Approach 2: Pipe Name-to-Class Mapping (More Explicit)
If you want to avoid relying on PipeResolver (or need more control over which pipes are accessible dynamically), you can create a mapping object that links pipe names to their corresponding classes.
Example Implementation
Create a mapping of pipe names to their classes:
import { UpperCasePipe, DatePipe } from '@angular/common'; import { MyCustomPipe } from './my-custom.pipe'; // Your own custom pipe const pipeRegistry: Record<string, any> = { 'uppercase': UpperCasePipe, 'date': DatePipe, 'myCustomPipe': MyCustomPipe };In your component, use the injector to fetch the pipe instance and invoke it:
ngOnInit() { const targetPipeName = 'myCustomPipe'; const value = 'test value'; const pipeArgs = ['customArg1', 123]; const pipeClass = pipeRegistry[targetPipeName]; if (!pipeClass) { throw new Error(`Pipe ${targetPipeName} not found in registry`); } const pipeInstance = this.injector.get(pipeClass) as PipeTransform; const result = pipeInstance.transform(value, ...pipeArgs); }
This approach is great for scenarios where you want to restrict dynamic pipe access to a predefined set, or if you prefer more explicit control over pipe resolution.
Key Difference from AngularJS
While AngularJS let you call $filter directly with a string, Angular's approach requires resolving the pipe class first (either via PipeResolver or a manual map) before getting an instance via the injector. This aligns with Angular's dependency injection and module system, but achieves the same dynamic invocation goal.
内容的提问来源于stack exchange,提问作者Shridhar L

