我计划提供一个可以使用模板等管道的服务。为此,我需要获得注册的管道。
代码最终应该如下所示:
@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];
}
}
问题是你无法从注射器中取出管道。您必须先提供它们(一次用于指令,一次用于提供者)。我正在寻找一种方法来从角度(编译器,核心 - 无论如何。某处必须是列表 - 可能是根模块)而不是定义新列表。
答案 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的说明,在编译器之外无法注入。
因此,最终应根据开发人员的需求和管道的内部结构,逐管解决。精心设计的管道通常是相关文档服务的薄包装,一个好的做法是尽可能直接使用这些服务。