我正在尝试从/users
列表中检索数据并收到此错误:
类型'订阅'不能分配给类型 'FirebaseListObservable'。类型中缺少属性'$ ref' '订阅'。
下面是我的代码:
import { Injectable } from '@angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
import firebase from 'firebase';
import { AngularFireDatabase, FirebaseListObservable, FirebaseObjectObservable } from 'angularfire2/database';
@Injectable()
export class FbauthserviceProvider {
user : FirebaseListObservable<any>;
email: string;
constructor(public afAuth: AngularFireAuth, public afDb: AngularFireDatabase) {
console.log('Hello FbauthserviceProvider Provider');
}
signup_with_username(email: string,password: string){
this.email = email;
this.user = this.afDb.list('/users', {
query: {
orderByChild: 'email',
equalTo: this.email,
},
preserveSnapshot: true
}).subscribe(snapshots => {
let user_data = [];
snapshots.forEach(snapshot => {
user_data.push(snapshot.val());
});
console.log(user_data);
});
}
}
答案 0 :(得分:1)
你的代码充斥着反模式和不必要的部分。
首先,不要使用preserveSnapshot
。您不需要使用AngularFire。您可以直接订阅FirebaseListObservable
发出的数组本身。一旦你拥有它,就没有必要迭代它并将其元素推送到其他一些数组 - 你已经有了数组,你可以按原样使用,或者映射,或存储(但见下文),或者其他什么。所以写一下:
this.user = this.afDb.list('/users', {
query: {
orderByChild: 'email',
equalTo: this.email,
}})
}).subscribe(users => {
console.log("users are", users);
});
但这里仍有问题。 this.user
不是您的意思:它将是subscribe
返回的订阅。除了取消订阅之外,您无法对其进行任何操作。如果要“解包”用户列表并将其存储为本地静态属性,则需要在subscribe
处理程序中将其分配给可用的位置:
.subscribe(users => {
console.log("users are", users);
this.users = users;
})
然而,展开observable并将其存储在静态属性中(通常)是一种反模式。问题是你不知道什么时候准备就绪。在最好的情况下,您必须在模板中包含与*ngIf="users"
一起使用的位置,或者使用?
中的存在性运算符users?.length
来限定模板中对它的引用(这不是AoT友好的。)
相反,保持observable不变,并使用async
管道直接在模板中取消引用它:
this.users$ = this.afDb.list('/users', {
query: {
orderByChild: 'email',
equalTo: this.email,
}});
<div *ngFor="let user of users$ | async">
User is {{user.name}}
</div>
这里我遵循使用$
表示可观察对象的后缀属性约定,这对于保持理智是有用的。
如果您只想要名称,那么您可以映射observable本身以创建一个可观察的名称数组:
this.names$ = this.users$.map(users => users.map(user => user.name));
请注意,这两个map
来电不同。第一种是将 observable 映射到新的observable。第二个是将observable的用户数组 emit 映射到包含名称的新数组。现在在您的模板中:
<li *ngFor="let name of names$">{{name}}</li>
上面的讨论涉及组件。在您的情况下,您有一项服务。通常,服务的反模式是订阅一些可观察的并将值存储在静态本地属性中。问题是不会更新引用该服务上的属性的组件。相反,您的服务应该公开observables,并让消费者 - 通常是一个组件 - 解除引用/解包它们。
要查找手机号码匹配的用户,您仍然可以留在可观察的世界中:
this.matchingUsers$ = this.users$.map(users => users.filter(user => user.mobile === mobile));
将创建具有匹配移动号码的用户数组的可观察对象,如果没有匹配则将为空。一些消费模板可以将其用作
<div *ngFor="let matchingUser of userService.matchingUsers$ | async">
Found matching user {{user.name}}
</div>
或
<div *ngIf="userService.matchingUsers$ | async as matchingUsers">
<div *ngIf="!matchingUsers.length">
Sorry, no matching users.
</div>
</div>
等等。请注意,此as
语法需要Angular 4。
这是Angular / observable / AngularFirebase方式。
答案 1 :(得分:0)
subscribe
函数返回一个Subscription对象。
您正在分配FirebaseListObservable
参考。
而是在分配后订阅,如果您需要重用observable。
this.user = this.afDb.list('/users',{
query: {
orderByChild: 'email',
equalTo: this.email,
},
preserveSnapshot: true
})
this.user.subscribe(snapshots =>{
let user_data = [];
snapshots.forEach(snapshot=>{
user_data.push(snapshot.val());
});