sniffer
@sniffer
front-end developer

Как динамически применять дефолтныe pipe?

Задача следующая:
Есть массив объектов. У каждого объекта есть поле pipe: string. Например, { name: 'Test', pipe: 'lowercase' }.
Во view я вывожу список объектов и хочу, чтобы к каждому объекту применялся pipe, который указан в объекте.

<span *ngFor="let item of items">{{ item.name | item.pipe }}</span>


В качестве pipe планирую использовать только дефолтные, кастомные pipe не нужны.
Возможно ли такое реализовать? Каким образом лучше это сделать?
  • Вопрос задан
  • 147 просмотров
Решения вопроса 2
Illorian
@Illorian
Front-end разработчик
Так навряд ли получится, потому что ангуляр делает бинды на этапе компиляции. По идеи он вообще должен на это выдать ошибку. Так что самый простой способ инжектить пайпы в компонент и применять их прямо там.
Ответ написан
Вариант 1
Использовать кастомный pipe Живой пример:
import { UpperCasePipe, LowerCasePipe } from '@angular/common'

const PIPES_COLLECTION = {
  'uppercase': new UpperCasePipe(), 
  'lowercase': new LowerCasePipe()
};

@Pipe({
  name: 'dynamicPipe'
})
export class DynamicPipe implements PipeTransform {
  transform(val, pipeName: string) {
    return PIPES_COLLECTION[pipeName].transform(val);
  }
}


Минус в том, что нужно вручную перечислять доступные наборы пайпов
___________________________________________________________________________________________________________________

Вариант 2
Использовать директиву, которая динамически генерирует результат через Compiler Живой пример

Минусы - генерируется лишняя разметка, нужно больше времени на компиляцию и не будет работать с AOT
@Directive({
  selector: '[dynamicPipe]'
})
export class DynamicPipeDirective {
  @Input() dynamicPipe: DynamicPipeModel;
  cmpRef: ComponentRef<any>;

  constructor(private vcRef: ViewContainerRef, private compiler: Compiler) {}

  ngAfterViewInit() {
    const data = this.dynamicPipe.name;
    const pipe = this.dynamicPipe.pipe;

    @Component({
      selector: 'dynamic-comp',
      template: '{{ data | ' + pipe  + '}}'
    })
    class DynamicComponent  {};

    @NgModule({
      imports: [CommonModule],
      declarations: [DynamicComponent]
    })
    class DynamicModule {}

    this.compiler.compileModuleAndAllComponentsAsync(DynamicModule)
      .then((moduleWithComponentsFactory) => {
        const compFactory = moduleWithComponentsFactory.componentFactories.find(x => x.componentType === DynamicComponent);
        const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
        this.cmpRef = this.vcRef.createComponent(compFactory, 0, injector, []);
        this.cmpRef.instance.data = data;
      });
  }

  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }
  }
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы