创建自己异步的自定义管道

时间:2018-07-23 14:47:37

标签: angular

我创建了一个自定义管道,可以从API检索文本内容,如下所示:

@Pipe({ name: 'apiText' })
export class ApiTextPipe implements PipeTransform {
  constructor(private myApiService: MyApiService) {
  }

  transform(key: string): Observable<string> {
    return this.myApiService.getText(key);
  }
}

我必须像这样使用它:

<strong>{{'some-key' | apiText | async}}</strong>

但实际上,我将总是 想要组合apiTextasync管道。我更愿意这样写:

<strong>{{'some-key' | apiTextAsync}}</strong>

我能以某种方式做到这一点,并通过组合两个管道使事情变得更干燥吗?

1 个答案:

答案 0 :(得分:3)

几个评论者指出(正确地如此),这违反了SRP,并可能会损害可读性。但是,即使这会让我重新考虑是否想要,我仍然肯定想知道如何 如果需要的话。我找到了两个解决方案(再次在评论者的帮助下)。

组成(不推荐)

创建自己的内部AsyncPipe并使用它。这是应该工作的基本设置:

@Pipe({ name: 'apiText', pure: false })
export class ApiTextPipe implements PipeTransform, OnDestroy {
  private asyncPipe: AsyncPipe;

  constructor(private myApiService: MyApiService, private injector: Injector) {
    this.asyncPipe = new AsyncPipe(injector.get(ChangeDetectorRef));
  }

  ngOnDestroy() {
     this.asyncPipe.ngOnDestroy();
  }

  transform(key: string): string {
    return this.asyncPipe.transform(this.myApiService.getText(key));
  }
}

除了上述缺点(评论者指出)之外,我还看到其他问题:

  • 如果AsyncPipe发生更改,例如它开始实现OnInit,然后我们自己的管道也需要更改。您可能会错过这一点。将管道的实现以这种方式耦合到AsyncPipe并不是很好。

  • 我似乎无法注入AsyncPipe,因为它依赖于特殊的ChangeDetectorRef,所以我使用了this suggested approach直接从注入器询问。 (也许有更好的方法可以做到这一点,但我暂时不做进一步的挖掘……)

继承(不推荐)

您也可以尝试在自己的管道中extends AsyncPipe,但是那条路线的代码更加笨拙,将您的管道与异步管道紧密耦合。我尝试这种方法时遇到了一些问题:

  • 您再次需要ChangeDetectorRef才能传递到super(...)通话
  • 您需要紧密结合transformAsyncPipe方法的签名
  • transform变得非常复杂,因为它不再只需要一个字符串(请参见上一点)
  • 我不知道是否可以正确地使Angular调用超类的ngOnDestroy方法

加上我忘了的其他东西。我觉得代码很讨厌,甚至共享它似乎也不明智。

复制源(不推荐)

正如评论者之一所建议的,the source for AsyncPipe是开放的。因此,您可以采用它并以此来构建自己的管道。

出于明显的原因,这不是一个明智的决定。


最重要的是,我现在对我自己的问题的回答(尽管我很高兴地证明另一个答案是错误的!)是,这不容易实现,最好的解决方案是不解决任何问题:坚持坚持模板中的管道。

相关问题