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
- Å sende røret direkte gjennom en variabel som
<!-- html -->
<span *ngIf="element.pipe">{{ row[element.column] | element.pipe }}</span>
- 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>
- 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.
