[Angular RxJS] Single data observable pattern (combineLatest with startWith)

For example we have multi API calls for one single page. 

this.course$ = this.coursesService.loadCourseById(courseId)
this.essons$ = this.coursesService.loadAllCourseLessons(courseId)

 

This results multi <ng-container> in html:

  <ng-container *ngIf="(course$ | async) as data">
      <ng-container *ngIf="(lessons$ | async) as data">
        ...
      </ng-container>
   </ng-container>
 

 

To avoid using multi ng-container, we can use single data observable pattern:

复制代码
        const courseId = parseInt(this.route.snapshot.paramMap.get("courseId"));

        const course$ = this.coursesService.loadCourseById(courseId)
        const lessons$ = this.coursesService.loadAllCourseLessons(courseId)

        this.data$ = combineLatest([course$, lessons$])
            .pipe(
                map(([course, lessons]) => {
                    return {
                        course,
                        lessons
                    }
                }),
                tap(console.log)
            );
复制代码

We use 'combineLatest' to merge two observable, and results in one single observable.

 

But this brings one performance problem. Because 'combineLatest' need to wait both inner-obervables emit value then emits the final value. We end up wait all the data coming back from server. 

Let's say, course$ should be resolved faster then lessons$, and we want to display the content related to coure$, then when the lessons$ data coming back, we display the content related to lesons$.

To solve the problem, we can let both observable emit a init value, then when the data for inner-observable coming back, it will be merged one by one.

复制代码
  ngOnInit() {

        const courseId = parseInt(this.route.snapshot.paramMap.get("courseId"));

        const course$ = this.coursesService.loadCourseById(courseId)
            .pipe(
                startWith(null)
            );

        const lessons$ = this.coursesService.loadAllCourseLessons(courseId)
            .pipe(
                startWith([])
            );

        this.data$ = combineLatest([course$, lessons$])
            .pipe(
                map(([course, lessons]) => {
                    return {
                        course,
                        lessons
                    }
                }),
                tap(console.log)
            );


  }
复制代码
复制代码
  
<ng-container *ngIf="(data$ | async) as data">

    <div class="course">

        <h2>{{data.course?.description}}</h2>

        <img class="course-thumbnail" [src]="data.course?.iconUrl" *ngIf="data.course">

        <table class="lessons-table mat-elevation-z7" *ngIf="data.lessons.length">

            <thead>

            <th>#</th>
            <th>Description</th>
            <th>Duration</th>

            </thead>

            <tr class="lesson-row" *ngFor="let lesson of data.lessons">
                <td class="seqno-cell">{{lesson.seqNo}}</td>
                <td class="description-cell">{{lesson.description}}</td>
                <td class="duration-cell">{{lesson.duration}}</td>
            </tr>

        </table>

    </div>

</ng-container>
复制代码

 

posted @   Zhentiw  阅读(600)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2018-04-19 [Angular] Advanced DI
2018-04-19 [Angular] Freshness Caching Policy - Network First, Cache Last
2018-04-19 [Angular] Performance Caching Policy - Cache First, Network Last
2017-04-19 [tmux] Automate your workflow using tmux scripts
2017-04-19 [Javascript] Case insensitive sorting for string arrays
2016-04-19 [AngularJS] Using $parse Service
2016-04-19 [Angular 2] Child Router
点击右上角即可分享
微信分享提示