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>
  • 相关阅读:
    [转]rdlc报表中表达式的使用--switch和IIF范例
    [转]关于ASP.NET(C#)程序中TEXTBOX下动态DIV跟随[AJAX应用]
    CodeForces
    NYOJ306 走迷宫(dfs+二分搜索)
    全心全意为人民服务体如今我们软件设计上
    2014年麦克阿瑟基金奖,张益唐入围(62万美金用于个人支配)
    Android中SharedPreferences函数具体解释
    drupal7中CKEditor开启上传图片功能
    JBoss+Ant实现EJB无状态会话bean实例
    c#读取xml文件配置文件Winform及WebForm-Demo具体解释
  • 原文地址:https://www.cnblogs.com/Answer1215/p/12729393.html
Copyright © 2011-2022 走看看