【发布时间】:2020-06-14 15:44:30
【问题描述】:
我想创建一个 LoaderDirective,它可以获取和观察,加载数据同时显示一个微调器,当它加载时,它将微调器更改为原始数据,同时使用“as”关键字公开加载的数据。
我想这样使用它:<div *load="items$ as items">
这是我目前所拥有的:
@Directive({
// tslint:disable-next-line:directive-selector
selector: '[load]',
})
export class LoadDirective<T> {
private data: T;
@Input()
set load(observable: Observable<T>) {
observable.subscribe({
next: value => this.loaded(value),
error: error => this.showError(error)
});
}
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver
) {
this.viewContainer.clear();
this.viewContainer.createComponent(this.componentFactoryResolver.resolveComponentFactory(SpinnerComponent));
}
private loaded(value: T) {
this.data = value;
this.viewContainer.clear();
this.viewContainer.createEmbeddedView(this.templateRef, {load: this.data});
}
private showError(e: string) {
this.viewContainer.clear();
const errorComponent = this.viewContainer.createComponent(this.componentFactoryResolver.resolveComponentFactory(ErrorComponent));
errorComponent.instance.error = e;
}
}
问题是输入数据是可观察的,所以它期望输出是可观察的。有没有比管道上的TransformPipe 类似的方法来改变它?我该如何解决这个问题?
【问题讨论】:
-
我可以使用 async pip 来做到这一点,但如果我可以在指令中做到这一点,我发现这是多余的
-
我可以通过将
load()重命名为loadFor()来创建解决方法,然后像这样调用它:<div *load="let items for items$">。不是我要找的东西,所以我会保持这个问题的开放性。 -
我只是好奇:为什么要创建指令而不是组件?
-
我想要做的是使用加载的 observable(或观察到的项目)而不手动订阅组件并编写所有样板。我认为如果我只使用异步管道和 ngIf:
<div *ngIf="obs$ | async as loaded; else spinner"> <!-- do things with loaded --> </div> <ng-template #spinner>会更好。但是,如果我可以编写自己的指令来跳过实现我自己的异步管道,那么这是多余的:<div *load="items$ as items">。这让我可以在 div 内的任何地方使用items,这是我想要的 -
没有用于订阅 observables 和存储结果的样板,没有额外的组件,非常漂亮和干净的代码,只订阅一次并且结果存在于范围内。
标签: angular typescript rxjs angular-directive