仅知道名称时从Injector接收管道 [英] Receiving a pipe from Injector when only name is known

查看:35
本文介绍了仅知道名称时从Injector接收管道的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我计划提供可以使用管道(如模板)的服务.为此,我需要获取已注册的管道.

I plan to have a service that can use pipes like templates. For this propose I need to get the registered pipes.

最后,代码应如下所示:

The code should look like this in the end:

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

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

The problem is that you can't get pipes from injector. You have to provide them first (once for directives and once of providers). I'm looking for a way to get them from angular (compiler, core - what ever. somewhere have to be a list - may be for the root module) instead of defining a new list.

推荐答案

在Angular中没有干净的惯用方式来获取这种方式的管道.只是因为它们由编译器在内部使用,并且没有暴露给注入.如果应该使用注入器注入管道,则应将其定义为提供者.

There's no clean idiomatic way in Angular to get a pipe this way. Just because they are used internally by compiler and not exposed for injection. If pipes are supposed to be injected with injector, they should be defined as providers.

由于管道是可注入的,因此使用注入器获取其实例是执行此操作的唯一正确方法.可以通过可用管道图来实现.

Since pipes are injectables, getting their instances with injector is the only proper way to do this. This can be implemented with a map of available pipes.

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

通过指定一系列管道类并使用

Filling the map can be automated by specifying an array of pipe classes and using PipeResolver to get their names:

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 是说明性的,

Since pipes are supposed to be instantiated by the compiler once per binding, injector.get(...) may not work for some pipes. AsyncPipe is illustrative in this case, it is stateful and also uses ChangeDetectorRef dependency, which isn't available for injection outside the compiler.

因此,最后应根据开发人员的需求和管道的内部情况,以每个管道为基础进行解决.设计良好的管道通常是相关记录服务的薄包装,一个好的做法是,如果可能的话,直接使用这些服务.

So in the end this should be solved on per pipe basis, depending on developer's needs and pipe's internals. Well-designed pipes are often thin wrappers for the relevant documented services, a good practice is to use these service directly if possible.

这篇关于仅知道名称时从Injector接收管道的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆