仅在知道名称时从Injector接收管道

时间:2017-04-13 12:00:52

标签: angular typescript

我计划提供一个可以使用模板等管道的服务。为此,我需要获得注册的管道。

代码最终应该如下所示:

@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];
    }
}

问题是你无法从注射器中取出管道。您必须先提供它们(一次用于指令,一次用于提供者)。我正在寻找一种方法来从角度(编译器,核心 - 无论如何。某处必须是列表 - 可能是根模块)而不是定义新列表。

1 个答案:

答案 0 :(得分:2)

在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, ...],
...

通过指定管道类数组并使用PipeResolver获取其名称,可以自动填充地图:

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在这种情况下是it is stateful and also uses ChangeDetectorRef dependency的说明,在编译器之外无法注入。

因此,最终应根据开发人员的需求和管道的内部结构,逐管解决。精心设计的管道通常是相关文档服务的薄包装,一个好的做法是尽可能直接使用这些服务。