【问题标题】:Combine ActivatedRoute observables with Observables from API requests将 ActivatedRoute 可观察对象与 API 请求中的可观察对象结合起来
【发布时间】:2020-10-16 19:24:56
【问题描述】:

我正在尝试使用 forkJoincombineLatest 组合两个 observables(到目前为止我的两个选项)。 一个 observable 来自 ActivatedRoute 的数据 (Observable<Data>),一个是对 API 的调用 (Observable<Project>)。

最初这两个是级联的,一切正常。但我认为结合这两个可观察值可能会有所改善。我知道激活路由中的 observable 尚未完成,每次用户浏览应用程序时都会触发它。当收到响应时,第二个 observable 完成。 forkJoin 适用于第二种类型的可观察对象(已完成的),combineLatest 适用于未完成的可观察对象,并采用它们的最新值。

有没有办法将这两者结合起来,或者级联方法是最好的方法?谢谢!

编辑: 我更新了代码以修复一些小问题并添加了数组解构。

但是,我发现当我在当前页面上刷新应用程序时,routeData 是一个空对象,但是如果我在设置 routeData 的位置添加断点(在 DevTools 选项卡 Source 中),它就可以工作。或者,如果我导航到设置路由数据的组件,它仍然可以工作。所以我猜一个小的延迟会让当前的 routeData 被填充?但是当实际数据放在路由上时,为什么没有再次触发呢? 我希望这不会太混乱

后期编辑: 我有 2 页及其各自的组件:资产管理 (AssetManagementComponent) 和项目管理 (ProjectManagementComponent)。 Project 组件是 Asset 组件的子组件。初始化资产组件后,我从 API 获取一些数据并将其放在 route.data 上。现在,当加载项目组件(子组件)时,我想从 API 获取该路由数据和一些额外的特定项目相关数据。

问题是如果我刷新项目管理页面,上面的代码将导致routeData 只是一个空对象{}。但是,如果我转到资产管理,然后转到项目管理,routeData 将包含正确的数据。

我尝试使用 DevTools 调试此问题,如果我在每个 ngOnInit() 函数中放置断点,即使我直接在 ProjectManagement 上刷新应用程序,它也会有正确的 routeData

更新:

这是最终的工作版本: route data observable 上添加 filter 修复了它,它似乎用一个空对象触发一次,然后用一个有效对象触发。

感谢大家的 cmets,我学到了新的东西和好的做法!祝你有美好的一天!

【问题讨论】:

  • 你有什么问题?您可以将它们与上面列出的选项结合使用。是时间问题还是什么?
  • 使用combineLatest,每次任何组合的 Observable 发出时,它都会发出来自 all Observable 的值。如果getProjectDetails Observable 只发出一次,combineLatest 将保留发出的值并在每次路由 Observable 发出时重新发出。我经常使用这种combineLatest 技术。 (顺便说一句,如果您使用数组解构 [routeData, project] 而不仅仅是 data,代码可能更具可读性。)
  • 有没有办法将这两者结合起来 - 但您已经在使用 combineLatest 来结合它们。你的方法已经很优雅了。我对@DeborahK 的评论还有一件事。在combineLatest 开始发射之前,所有源可观察对象必须至少发射一次。因此,如果您认为遗漏了其中一个可观察对象的某些排放,您可以将 startWith 操作符传递给开始延迟发射的可观察对象以启动 combineLatest
  • 确实,我错过了问题。因此,组合工作但缺少第一个数据,可观察的路由只返回一个空对象{}。也非常感谢你的解构建议,很漂亮
  • 另外还有一个bug,在设置this.project之前用this.project调用processRelatedEntities函数,刚刚发现

标签: angular typescript rxjs


【解决方案1】:

如果我理解正确,我会采取这种方式来利用mergeMap。 听起来正在发生的事情是您的 activeRoute 订阅第一次刷新时它是空的,然后它获取数据并发送第二个数据。

这种方法将过滤掉所有没有资产的路由参数,一旦它通过过滤器,我们将其合并映射到下一个请求,这样我们就可以将它传递到最终的地图,在那里你有两个值应该总是如果达到该代码,则填充。

所以这样的事情可能更适合你。

this.route.parent.data.pipe(
  filter(routeData => routeData && routeData.asset), //make sure route data is there
  mergeMap(routeData =>{
    return this.projectService.getProjectDetails(projectId).pipe.map(project =>{
       return {routeData, project}
    })
  }),
  map(data => {
    // now you should have access to data.routeDate and data.project
     
  })
).subscribe()

希望这有助于 routeParams 在您需要该值来进行另一个调用时可能会很棘手。 我认为该代码是正确的,但为时已晚,我只是从记忆(和谷歌)中回忆起,哈哈

【讨论】:

  • filter(routeData => routeData && routeData.asset) 是缺失的部分。我已将其添加到route.data,现在效果很好。谢谢你,先生!
猜你喜欢
  • 1970-01-01
  • 2016-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多