【问题标题】:async pipe not subscribing to Observable Angular异步管道未订阅 Observable Angular
【发布时间】:2021-05-28 21:53:09
【问题描述】:

在 Angular (v12) 中,我有以下组件(使用虚拟变量名称):

export class DataDetailsComponent {
    data$: Observable<MyDataModel>;

    constructor(dataService: DataService, route: ActivatedRoute, private router: Router) {
        this.data$ =
            combineLatest([dataService.getDataObservable(), router.events])
                .pipe(
                    filter(([,event]) => event instanceof ActivationEnd),
                    tap(([data, event]) => console.log((<ActivationEnd>event).snapshot.queryParams['id'])),
                    map(([data, event]) => data.filter(c => c.id === (<ActivationEnd>event).snapshot.queryParams['id'])[0]),
                    tap(dataItem => console.log(dataItem))
                );
        this.data$.subscribe(); // console.logs don't work without this
    }
}

及其模板:

<div *ngIf="data$ | async as data; else loading">
    <img [src]="data.url" [alt]="data.name">
</div>
<ng-template #loading>Loading...</ng-template>

如果我实际上没有订阅data$,则不会呈现数据,并且浏览器控制台为空。另一方面,当我放置 this.data$.subscribe(); 时,控制台会得到正确的输出,但视图仍然是空的(挂在 Loading... 上)。

谁能解释这是怎么回事?

【问题讨论】:

  • 也许你的 observable 返回了假值,使得 *ngIf 评估为假?
  • 尝试combineLatest([dataService.getDataObservable(), router.events]).subscribe(console.log))获取更多信息
  • @AllanJuan 但是当我手动订阅时,我从tap(console.log(...)) 得到了非常真实的值...
  • 可能是一个长镜头,但值得尝试将设置代码移动到 ngOnInit 以确保它与某些未初始化的组件状态无关。如果将真实的 observable 替换为 dummy of(true) 会发生什么?
  • 另一个想法。首先,请注意构造函数中的订阅和 ngFor 中的订阅将在不同的时间发生,因此从 combineLatest 返回的值可能不同。尝试在过滤器之前再次点击 - 当 ngFor 订阅时,如果 combineLatest 没有发出,或者它被过滤掉,那么你会看到你所看到的。您也可以尝试“startWith”来检验假设。

标签: angular rxjs angular-router angular2-observables async-pipe


【解决方案1】:

可以与您的 combineLatest 相关。检查两个可观察对象都在发出数据。

结合最新定义:

请注意,combineLatest 不会发出初始值,直到每个 observable 发出至少一个值。这是相同的行为 withLatestFrom 并且可能是一个陷阱,因为不会有输出,也没有 错误,但您的一个(或多个)内部可观察对象可能不是 按预期运行,或订阅延迟。

您可以使用 startWith 运算符为可观察对象设置一些初始值。

【讨论】:

  • 我 100% 确定数据存在。这是从数据列表访问的详细信息组件,因此数据已经加载到服务上。此外,服务在BehaviorSubject&lt;T&gt; 中保存数据,所以我不得不在构造函数中使用初始值。
【解决方案2】:

最后,是路由器事件没有让 observable 完成。 显然,如果我将导航从模板移动到 .ts 并订阅 ActivatedRoute.params 而不是 Router.events,它会起作用。

所以,父组件得到:

navigateToDetails(id: string): void {
    this.router.navigate(['/myRoute', id]);
}

而不是在模板中使用routerLink

<a [routerLink]="['/myRoute']" [queryParams]="{id: item.id}">

然后,在DataDetailsComponent 我可以做到:

constructor(dataService: DataService, route: ActivatedRoute) {
        this.data$ =
            combineLatest([dataService.getDataObservable(), route.params])
                .pipe(map(([data, params]) => data.filter(c => c.id === params['id'])[0]));
    }

目前我无法理解的原因。

【讨论】:

    猜你喜欢
    • 2020-11-13
    • 2021-11-04
    • 1970-01-01
    • 2019-05-06
    • 1970-01-01
    • 2017-11-30
    • 2016-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多