有没有办法在 HTML 中动态注入管道?角9

big*_*_OS 7 typescript angular-pipe angular


我正在构建一个抽象表组件的主题,我将其在某些列中应使用的管道传递给该组件。由于传递的数据可能会有所不同,因此管道也应该有所不同。

目标
使用传递到表的任何管道

在我看来,该项目
在 html 中应该是这样的

<!-- html --> 

<span *ngIf="element.pipe">{{ row[element.column] | <<here_inject_an_appropriate_pipe>> }}</span>
Run Code Online (Sandbox Code Playgroud)

列设置通过对象传递,形式为

//typescript  

columnSettings: [
    ...
    {column: 'fruitExpDate', caption: 'Best before', pipe: 'date: \"' + PIPE_DATE_FORMAT + '\"' },
    ...
]
Run Code Online (Sandbox Code Playgroud)

PIPE_DATE_FORMAT持有字符串'yyyy-MM-dd'

我尝试过的

  1. 直接通过变量传递管道,例如
<!-- html --> 

<span *ngIf="element.pipe">{{ row[element.column] | element.pipe }}</span>
Run Code Online (Sandbox Code Playgroud)
  1. 创建将另一个管道作为参数的自定义管道
@Pipe({
    name: 'dynamicPipe',
})
export class DynamicPipe implements PipeTransform {
    // constructor(private abstractTableService: AbstractTableService) {}

    transform(value: any, pipe: string): any {
        const pipeToken: any = pipe.split(':')[0].replace(/[\s]+/g, '');
        const pipeArgs: any = pipe.split(':')[1].replace(/[\s]+/g, '');

        console.log(value);
        console.log(pipe);

        // return pipeToken.transform(value, ...pipeArgs);
        return 'check pipe';
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我尝试了许多不同的方法来调用请求的管道,但最终不知道如何做到这一点。这是我的带有自定义管道的 html:

<!-- html --> 

<span *ngIf="element.pipe">{{ row[element.column] | dynamicPipe: element.pipe }}</span>
Run Code Online (Sandbox Code Playgroud)
  1. 创建自定义服务来调用导入的管道
@Injectable()
export class AbstractTableService {
    constructor(
        private date: DatePipe,
    ) {}

    getDatePipe(): DatePipe {
        return this.date;
    }
}
Run Code Online (Sandbox Code Playgroud)

但在这里我不知道如何有效地使用这项服务。

Abo*_*odz 12

您需要在动态管道内创建所选管道的实例。为此,您可以使用 Angular 注入器。动态管道(我称之为)可以是这样的:

import { Pipe, PipeTransform, Injector, Type } from '@angular/core';

@Pipe({
  name: 'dynamicPipe'
})
export class DynamicPipe implements PipeTransform {

  constructor(private injector: Injector) {}

  transform(value: any, requiredPipe: Type<any>, pipeArgs: any): any {
    const injector = Injector.create({
      name: 'DynamicPipe',
      parent: this.injector,
      providers: [
        { provide: requiredPipe }
      ]
    })
    const pipe = injector.get(requiredPipe)
    return pipe.transform(value, pipeArgs);
  }

}
Run Code Online (Sandbox Code Playgroud)

确保将管道类(类型)作为参数传递,而不是其名称的字符串表示形式。如果您要传递一个字符串,假设数据来自服务器端,您可能需要考虑为其创建一个映射。

可以在这里找到完整的工作示例: https ://stackblitz.com/edit/angular-ivy-evzwnh

这是一个粗略的实现。我不确定 Tree-Shaking 的情况。它需要更多的测试和优化。