我创建了一个自定义管道,可以从API检索文本内容,如下所示:
@Pipe({ name: 'apiText' })
export class ApiTextPipe implements PipeTransform {
constructor(private myApiService: MyApiService) {
}
transform(key: string): Observable<string> {
return this.myApiService.getText(key);
}
}
Run Code Online (Sandbox Code Playgroud)
我必须像这样使用它:
<strong>{{'some-key' | apiText | async}}</strong>
Run Code Online (Sandbox Code Playgroud)
但实际上,我将始终希望结合使用apiText和async管道。我更喜欢这样写:
<strong>{{'some-key' | apiTextAsync}}</strong>
Run Code Online (Sandbox Code Playgroud)
我能以某种方式做到这一点,并通过组合两个管道使事情变得更干燥吗?
更新:我已打开GitHub问题作为对此功能的解决方案的功能要求。
max*_*dev 10
无需复制async管道转换的源,您真正需要的唯一东西是pure: false属性和ChangeDetectorRef.
这是一个最小的例子:
import { ChangeDetectorRef, Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'example',
pure: false
})
export class ExamplePipeTransform implements PipeTransform {
value?: string;
constructor(private _ref: ChangeDetectorRef) {}
transform(value: any): unknown {
if (!this.value) {
this.value = value;
// Just an example for some async operation:
setTimeout(() => {
// In the callback do this:
this.value = value;
this._ref.markForCheck();
}, 1000);
}
return this.value;
}
}
Run Code Online (Sandbox Code Playgroud)
一旦您想要执行的异步操作完成,您就可以存储该值并简单地调用ChangeDetectorRef.markForCheck. 这将导致transform再次被调用。
这里setTimeout只是一个示例,您可以执行Observable.subscribe然后返回解析值。
一些评论者指出(正确地如此),这违反了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));
}
}
Run Code Online (Sandbox Code Playgroud)
除了上述缺点(评论者注意到)之外,我还看到其他问题:
如果AsyncPipe发生了变化(例如,它开始实现)OnInit,那么我们自己的管道也需要更改。您可能会错过这一点。我们管道的实现以这种方式耦合到AsyncPipe不好。
我似乎无法AsyncPipe注射,因为它依赖于special ChangeDetectorRef,所以我使用了这种建议的方法,直接从注射器中询问它。(可能有更好的方法来执行此操作,但是我现在不进一步探讨...)
继承(不推荐)
您也可以尝试extends AsyncPipe在自己的管道中进行操作,但是该路线的代码更加笨拙,将您的管道与异步管道紧密耦合。当我尝试这种方法时,存在一些问题:
ChangeDetectorRef转接到super(...)通话transform方法的签名AsyncPipetransform得到超级复杂,因为它不再只是需要一个字符串(参见前一点)ngOnDestroy方法再加上我忘记的一切。我觉得代码很讨厌,甚至共享它似乎也不明智。
复制源(不推荐)
正如评论者之一建议的那样,的来源AsyncPipe是开放的。因此,您可以采用它并以此构建自己的管道。
由于明显的原因,这不是明智的决定。
最重要的是,我现在对自己的问题的答案(尽管我很高兴地证明另一个答案是错误的!)是,这不容易实现,最好的解决方案是不解决任何问题:只需坚持使用二重奏模板。