zoukankan      html  css  js  c++  java
  • [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>
  • 相关阅读:
    List、Set、Map集合大杂烩
    Android的DatePicker和TimePicker-android学习之旅(三十八)
    Ubuntu 启动项、菜单 改动 防止隐藏
    Ehcache 整合Spring 使用页面、对象缓存
    Spring MVC 相关资料整理
    Spring + Spring MVC+Hibernate框架整合详细配置
    @RequestMapping 用法详解之地址映射
    关于时间统计问题
    Oracle之物化视图
    Oracle:高效插入大量数据经验之谈
  • 原文地址:https://www.cnblogs.com/Answer1215/p/12729393.html
Copyright © 2011-2022 走看看