typescript - Finnes det en måte å injisere pipes i HTML dynamisk? Angular 9


Emnet
Jeg bygger en abstrakt tabellkomponent som jeg sender inn hvilken pipe den skal bruke i bestemte kolonner. Siden dataene som sendes inn kan variere, bør også pipene variere.

Målet
Å bruke hvilken som helst pipe som blir sendt til tabellen

Prosjektet
Slik mener jeg det skal se ut i HTML

<!-- html --> 

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

Kolonneinnstillingene overføres gjennom et objekt og har formen

//typescript  

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

og PIPE_DATE_FORMAT inneholder strengen 'yyyy-MM-dd'

Hva jeg prøvde

  1. Å sende røret direkte gjennom en variabel som
<!-- html --> 

<span *ngIf="element.pipe">{{ row[element.column] | element.pipe }}</span>
  1. Opprette en tilpasset pipe som tar en annen pipe som et argument
@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';
    }
}

og her prøvde jeg mange forskjellige ting for å kalle den forespurte pipen, men til slutt fant jeg ikke ut hvordan jeg skulle gjøre dette. Her er min HTML med den tilpassede pipen:

<!-- html --> 

<span *ngIf="element.pipe">{{ row[element.column] | dynamicPipe: element.pipe }}</span>
  1. Opprette en tilpasset tjeneste for å kalle importerte rør
@Injectable()
export class AbstractTableService {
    constructor(
        private date: DatePipe,
    ) {}

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

men her hadde jeg ingen anelse om hvordan jeg skulle bruke denne tjenesten effektivt.

Svar #1

Du må opprette en instans av den valgte pipen inne i en dynamisk pipe. For å gjøre det kan du bruke Angular-injektoren. Den dynamiske pipen (som jeg kaller den) kan være noe sånt som dette:

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

}

Sørg for å sende pipe-klassen (typen) som argumenter, ikke en strengrepresentasjon av navnet dens. Hvis du skal sende en streng, la oss si at dataene kommer fra server-siden, må du kanskje vurdere å opprette en mapping for det.

Et fullt fungerende eksempel kan finnes her: https://stackblitz.com/edit/angular-ivy-evzwnh

Dette er en grov implementering. Jeg er ikke sikker på Tree-Shaking. Det trenger mer testing og optimalisering.

Relaterte artikler