angular - 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[]'。“可观察”类型中缺少属性“包含”。我怎样才能解决这个问题?
解决方案
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 中管理订阅,并且一旦对服务器的调用完成,您的节目列表就会神奇地出现。
推荐阅读
- firebase - Fieldvalue.serverTimestamp() 可以代表未来“X”秒的时间吗?
- c# - 在 ASP.NET Core API 中使用身份的问题 [已解决]
- matlab - MATLAB:N大于1的polyval函数
- c - C中的动态内存访问冲突
- javascript - “mysql”数据库不支持“User.repositories”中的数据类型“Array”
- linux - 为什么这个脚本没有杀死 Docker 后台进程?
- php - 创建自定义帖子类型后的 Wordpress 错误
- c# - 如何在 C# 中获取 Comprehend Medical Job Request 的状态
- java - Android dateFormat.parse(date) 我发送 01/03/2021 它显示 sun dec 27 00:00:00 GMT-05:00 2020
- rust - 为什么即使在本地安装后,rust 也无法为 openssl-sys v0.9.60 构建命令?