【问题标题】:Safe navigation operator on an async observable and pipe in Angular 2Angular 2 中异步可观察对象和管道上的安全导航运算符
【发布时间】:2016-12-09 15:57:12
【问题描述】:

在异步加载的 observable 上使用安全导航运算符时,我遇到了一个问题,即 null 值(而不是 Lectures 数组)被传递到管道:

<div *ngFor="let lecture of ((lecturesObservable | async)?.lectures | lectureType: 'main')" class="list-group-item">

lecture-type.pipe.ts

import { Pipe, PipeTransform } from '@angular/core';

import { Lecture } from './lecture';

@Pipe({name: 'lectureType'})
export class LectureTypePipe implements PipeTransform {
    transform(allLectures: Lecture[], lectureType: string): Lecture[]{
        return allLectures.filter(lecture => lecture.type==lectureType);
    }
}

一旦被异步加载,讲座会在没有管道的情况下进行迭代。这只是我在 ng2 中必须忍受的东西吗?

【问题讨论】:

    标签: angular


    【解决方案1】:

    您还可以制作直接与 Observables 一起使用的 Angular 管道。然后您的过滤管道可以在 Observables 或“硬值”上运行。

    但是当它使用 observable 时 - 你永远不会得到错误,因为代码在 存在值之前不会运行。

    为此,在签名中(注意 any 是一个数组):

     transform(value: Observable<any> | any[])
    

    然后检查内部是否存在可观察值或“硬值”:

    @Pipe({ name: 'filterLectures' })
    export class FilterLecturesPipe implements PipeTransform {
    
        constructor() {}
    
        transform(value: Observable<any> | Array<any>, filterValue: any): Observable<any> | Array<any>
        {
            if (isObservable(value))
            {
                return value.pipe(filter(v => filterLecturesFunction(filterValue, v) ));
            } 
            else
            {
                return (value as Array<any>).filter(v => filterLecturesFunction(filterValue, v) );
            }
        }
    }
    

    然后你像这样使用它 - 又好又干净:

    但这可能是不好的做法,因为管道不应该真正了解您的数据模型。最好在客户端过滤并暴露各种可观察对象。

    另一种方法是创建一个具有默认值的通用“startWith”管道:

    @Pipe({ name: 'startWith' })
    export class StartWithPipe implements PipeTransform {
    
        constructor() {}
    
        transform(value: Observable<any> | any, defaultValue: any): Observable<any> {
            if (isObservable(value)) {
                return value.pipe(startWith(defaultValue));
            } else {
                throw Error('Needs to be an observable');
            }
        }
    }
    

    这仅适用于可观察对象,因此您必须将其放在异步之前:

    我不确定 official 关于管道使用 observables OR 值的指导,但如果我需要使用某些东西来处理 either an可观察的一个实际值。

    【讨论】:

      【解决方案2】:

      您也可以使用*ngIf 完全隐藏该块,并将异步管道放置在那里。

      请注意重要的添加 let 以分配给本地范围的变量。

      在您的 *ngFor 中,您使用该 newlectures 变量,它保证始终有一个值 - 因此您的管道不会看到空值。

      此外,您还可以“免费”获得“加载模板”

      <div *ngIf="(lecturesObservable | async)?.lectures; let lectures; else loadingLectures">
      
          <div *ngFor="let lecture of (lectures | lectureType: 'main')" class="list-group-item">        
              Lecture details...
          </div>
      
      </div>
      
      <ng-template #loadingLectures>
          Loading lectures!
      </ng-template>
      

      另请注意,*ngIf 可用于 &lt;ng-container&gt;,这不会向 DOM 添加任何内容。

      【讨论】:

      • 这太好了,谢谢@Simon_Weaver。不知道我可以在该检查可观察语句中分配一个局部变量。尽管我最初询问的代码早已被搁置,但实际上我昨天在检查和循环一个可观察对象(对可观察对象的两次调用)并放弃支持订阅 .ts - 这本来可以不必要!再次感谢。
      • 另一种选择是向 UI 公开讲座并设置默认值。例如。讲座$=service.lectures.pipe(startWith([]));在 ts 文件中。然后你可以使用讲座$ |异步
      【解决方案3】:

      您还可以使用例如 BehaviorSubject 提供默认值,这样 Angular 在尚未收到值时不会抛出异常。

      【讨论】:

      • 谢谢 - 我仍在努力掌握所有可观察的对象和主题,所以已经使用 @Douglas 的简单解决方案
      • 没有问题。这完全是你的决定:)
      【解决方案4】:

      当它的输入 observable 还没有值时,异步管道会根据设计解析为 null。所以是的,你必须忍受它,通过设计你的管道来处理空输入。

      【讨论】:

      • 谢谢@Douglas,很明显 - 以为我已经尝试过了,但很简单:转换中的 if(allLectures!==null) 效果很好!
      猜你喜欢
      • 2020-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-24
      相关资源
      最近更新 更多