有没有一种方法可以动态注入HTML中的管道?角度9

时间:2020-07-20 06:33:12

标签: angular typescript angular-pipe

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

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

项目
我认为这是html中的外观

<!-- html --> 

<span *ngIf="element.pipe">{{ row[element.column] | <<here_inject_an_appropriate_pipe>> }}</span>

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

//typescript  

columnSettings: [
    ...
    {column: 'fruitExpDate', caption: 'Best before', pipe: 'date: \"' + PIPE_DATE_FORMAT + '\"' },
    ...
]

PIPE_DATE_FORMAT包含字符串'yyyy-MM-dd'

我尝试过的事情

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

<span *ngIf="element.pipe">{{ row[element.column] | element.pipe }}</span>
  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';
    }
}

在这里,我尝试了许多不同的操作来调用请求的管道,但最终没有弄清楚如何执行此操作。这是我的带有自定义管道的html:

<!-- html --> 

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

    getDatePipe(): DatePipe {
        return this.date;
    }
}

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

4 个答案:

答案 0 :(得分:1)

管道不是字符串,因此您不能使用pipe:'date: \"' + PIPE_DATE_FORMAT + '\"'

您的第二种方法已经关闭,但是您需要使用一个开关盒

注1:在Angular 9中,您可以直接使用以下函数:formatDate,formatNumber,formatCurrency和formatPercent

import { formatDate,formatNumber,formatCurrency,formatPercent } from '@angular/common';


transform(value: any, pipe: string): any {
    const pipeToken: any = pipe.split(':')[0].replace(/[\s]+/g, '');
    const pipeArgs: any = pipe.split(':')[1].replace(/[\s]+/g, '');
    let result=value;
    switch (pipeToken)
    {
       case "date":
         result=formatDate(value,pipeArgs) //(*)
         break
       case "number"
         result=formatNumber(value,pipeArgs) //(*)
         break
       ...
    }
    return result;
}

(*)检查文档以了解如何使用这些功能,我编写了“伪代码”

注2:如果您创建具有两个属性pipeKing和args的“列对象”,则该行为会更好,

例如

  {
   column: 'fruitExpDate', 
   caption: 'Best before', 
   pipeKind: 'date'
   pipeArgs:[PIPE_DATE_FORMAT]
  }

答案 1 :(得分:1)

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

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);
  }

}

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

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

这是一个粗略的实现。我不确定摇树。它需要更多的测试和优化。

答案 2 :(得分:0)

尝试更改原始模型,并分离管道类型和管道参数。可以说,这对您很有帮助:

columnSettings: [
    ...
    {
      column: 'fruitExpDate', 
      caption: 'Best before', 
      pipeType: 'date', 
      pipeParams: PIPE_DATE_FORMAT 
    },
    ...
]

然后,您可以在html中编写“动态管道”逻辑,并直接使用现有管道:

<ng-container [ngSwitch]="element.pipeType">
   <ng-container *ngSwitchCase="'date'">{{ row[element.column] | date:element.pipeParams }}</ng-container>
   <ng-container *ngSwitchCase="'...'">...</ng-container>
   <some-element *ngSwitchDefault>...</some-element>
</ng-container>

答案 3 :(得分:0)

对于条件管道,您可以映射这些项目并进行相应的转换。

columnSettings: [
...
 {
   column: 'fruitExpDate', 
   caption: 'Best before', 
   pipeType: 'date', 
   pipeParams: PIPE_DATE_FORMAT 
 },
 ...
]


columnSettings = columnSettings.map((col) => {
   if(col.pipeType === 'date) {
      col.pipeVal = (new DatePipe).transform(col) // or whatever you want to pass
   } else if(col.pipeType === 'blah) {
      col.pipeVal = (new BlahPipe).transform(col) // or whatever you want to pass
   }
  return col;
})

现在在模板中,您不需要任何条件语句,而只需打印col.pipeVal