首页 > 解决方案 > Angular 中的 observable 是如何工作的?“可观察”类型中缺少属性“包含”

问题描述

我是 Angular5 的新手,我现在正在使用 Firebase 来获取数据以显示我的页面。我在 Google 上搜索了一些如何使用 AngularFire 从 firebase 获取数据的示例,但其中很多已经过时了。最后我发现我应该使用 Observables 并订阅它。

service.ts

 constructor(private db: AngularFireDatabase) {
  }

  shows: Show[] = [];

  getShows(): Show[] {
    const response = (this.db.list('show/data')
                     .valueChanges() as Observable<Show[]>)
                     .subscribe(
                        data => {
                          data.forEach(element => {
                            console.log(element);
                            console.log(typeof element);
                            this.shows.push(element);
                          });
                        }
                      );
    console.log(this.shows);
    return this.shows;
  }

我 console.log 我从 subscribe() 获取的数据和 subscribe() 函数中的数据。第二个console.log首先出现了一个空的[],然后subscribe()中的console.log出现了我从firebase获得的每个单独的对象。

从理论上讲,当我运行第二个console.log 时,this.shows 是空的,当它返回时没有获取任何数据并且页面不应该显示任何内容。但是,在应用程序组件中,当我运行服务获取节目时,我仍然可以获得我想要的信息并且页面按预期显示。为什么会这样?如何确定执行返回函数时 this.shows 是否为空?

另外,我像这样修改了我的代码。

//服务.ts

constructor(private db: AngularFireDatabase) {
  }

  shows: Observable<Show[]>;

  getShows(): Observable<Show[]> {
    const response = (this.db.list('show/data')
                     .valueChanges() as Observable<Show[]>);
    return response;
  }

// show.component.ts

shows: Show[] = [];

  ngOnInit() {
    this.getShows();
  }

  getShows(): void {
    this.showService.getShows().subscribe(
      data => {
        data.forEach(element => {
          console.log(element);
          console.log(typeof element);
          this.shows.push(element);
        });
      },
      err => console.error('Observer got an error: ' + err)
    );
  }

它给出了 observable 类型的错误不可分配给类型 'Show[]'。“可观察”类型中缺少属性“包含”。我怎样才能解决这个问题?

标签: angulartypescriptangular5observableangularfire2

解决方案


Observables 是库 RxJs 中的核心对象,JavaScript 的反应式扩展库https://rxjs-dev.firebaseapp.com/。Angular 是建立在 observables 之上的,它是学习 Angular 的一个非常重要的概念。基本上,一个可观察对象就像一个异步数组,其中元素随着时间的推移按顺序排列。当您订阅 Observable 时,每次有新元素从流中下来时,您的订阅功能就会运行。它非常类似于 JavaScript 或 jQuery 承诺,但随着时间的推移,它们可以长期存在许多项目。

一开始这可能是一个令人困惑的主题,但我在学习 RxJs 时发现的最有用的资源之一是http://rxmarbles.com/

你确实需要学习 RxJs 和 Observables 背后的概念才能成为一名优秀的 Angular 开发人员,这是一个比单个 StackOverflow 问题所能涵盖的主题要大得多的话题。

在您的情况下,您已经注册了一个订阅功能,以便在对服务器的调用收到响应时被调用。第二个 console.log 首先被调用,因为该函数仅在收到来自服务器的响应后才运行。

我建议您查看异步管道。您可以像这样在 TypeScript 中将 Observable 分配给组件的属性

show$ Observable<Show[]> = this.db.list('show/data');

然后在您的视图中,您可以使用异步管道管理订阅并将值分配给视图变量,例如

<ng-container *ngIf="show$ | async as shows">
    <div *ngFor="let show of shows">
        {{show}}
    </div>
</ng-container>

这样您就不必担心在 TypeScript 中管理订阅,并且一旦对服务器的调用完成,您的节目列表就会神奇地出现。


推荐阅读