Angular 仅知道名称时从喷油器接收管道

Angular 仅知道名称时从喷油器接收管道,angular,typescript,Angular,Typescript,我计划有一个服务,可以使用管道一样的模板。对于这个提议,我需要获得注册管道 代码最终应该是这样的: @Injectable() class MyService { construct(private injector: Injector) {} // text could be something like 'myDate | date' or 'aVariable | uppercase' public interpolate(text: string, params

我计划有一个服务,可以使用管道一样的模板。对于这个提议,我需要获得注册管道

代码最终应该是这样的:

@Injectable()
class MyService {
    construct(private injector: Injector) {}

    // text could be something like 'myDate | date' or 'aVariable | uppercase'
    public interpolate(text: string, params: object = {}): string {
      let p: number = text.lastIndexOf('|');
      if (p > -1) {
        let args = [this.interpolate(text.substring(0, p))];
        let pipeName = text.substr(p+1).trim();
        // how ever we get the rest of the args from pipeName
        pipe = this.getPipe(pipeName)
        pipe.transform.apply(pipe, args);
      } else {
         // how ever we interpolate the base
      }
    }

    private pipeInstances: any = {}
    private getPipe(pipeName) {
      if (!this.pipeInstances[pipeName]) {
        // how to get the pipe?
        this.pipeInstances[pipeName] = this.injector.get(PipesContainer).get(pipeName);
      }

      return this.pipeInstances[pipeName];
    }
}

问题是您无法从喷油器获取管道。您必须首先提供它们(一次用于指令,一次用于提供程序)。我正在寻找一种方法从angular(编译器、核心——什么都可以。必须有一个列表——可能是根模块)获取它们,而不是定义一个新的列表。

angular中没有干净的惯用方法来以这种方式获取管道。只是因为它们是由编译器内部使用的,而不是为注入而公开的。如果管道应注入注入器,则应将其定义为供应器

因为管道是可注入的,所以使用注入器获取它们的实例是唯一正确的方法。这可以通过可用管道的映射来实现

export const pipesMap = {
  some: SomePipe
}

export const pipesList = Object.values(pipesMap);

@Injectable();
export class Pipes {
  protected pipesMap = pipesMap;

  constructor(private injector: Injector) {}

  get(pipeName) {
    return this.injector.get(this.pipesMap[pipeName]);
  }
}

...
providers: [pipesList, Pipes, ...],
...
通过指定管道类数组并使用获取其名称,可以自动填充地图:

import {PipeResolver} from '@angular/compiler';

const pipeResolver = new PipeResolver();

export const pipesList = [
  SomePipe
];

export const pipesMap = pipesList.reduce((pipesMap, pipeClass) => {
  const pipeName = pipeResolver.resolve(pipeClass, true).name;
  pipesMap[pipeName] = pipeClass;
  return pipesMap;
}, {});

...
由于每个绑定都应该由编译器实例化一次管道,
injector.get(…)
可能不适用于某些管道
AsyncPipe
在本例中是说明性的,它不可在编译器外部注入


因此,最终应该根据开发人员的需求和管道的内部结构,在每个管道的基础上解决这个问题。设计良好的管道通常是相关文件服务的薄包装,一个好的做法是在可能的情况下直接使用这些服务。

如何称呼它?从不同的地方。从其他服务、管道和组件,实际需求是什么?我正在开发一个模块(角度转换器),在转换中可以使用参数。在xx语言中,可能需要使用管道。好的,这就是我提到的解决方法。谢谢你的回答,但这不是一个解决办法。如果不重构angular本身的某些东西,这可能真的是不可能的。如果这是结果,我将打开一个功能请求。我相信这是你能得到的最接近惯用的解决方案。让湿代码显式地枚举这些东西并不是件坏事,只要它是干净的、可维护的和可测试的,而它的干代码不是。我想可以通过编译器以某种方式对管道列表进行黑客攻击,但这将导致依赖于内部的东西(这是不好的),并将AoT搞得无法修复(这真的很糟糕).考虑到angular1选择的方向,功能请求不太可能改变某些内容。应该注意的是,即使在angular1中,如果不进行黑客攻击,也无法做到这一点,因为angular1更不受限制。在angular1中,您可以插入
$filter
,并在当前根本无法做到的情况下使用此功能也许一个特性请求会有它的原因。我发现了注入器的另一个大问题:可能是一个特定的管道每次都需要一个新实例(比如
AsyncPipe
,是的,我的
translatepe
),但我不知道如何使用分层注入策略。