angular - 使用 userId 的 Angular Firestore 应用程序查询不起作用
问题描述
我有一个带有 firebase 应用程序的 Angular 6 我有一个带有 observable 的 Service(我稍后希望多个订阅者监听这个相同的 observable),还有一个订阅这个 observable 的组件我试图实现的是获取 auth 对象,获取userId (UID) 并在数据库中搜索具有此 ID 的所有文档
该组件在 ngOnInit 钩子上调用 observable 但在阶段它仍然为空,所以我得到
无法读取未定义的属性“订阅”
问题是,如果我运行代码来填充订阅块内的可观察对象(以获取身份验证数据),我看不到数据,如果它在它之外(使用静态 UID 运行同步),它确实被填充正确并在此处显示数据是服务的代码
import { Injectable, EventEmitter } from '@angular/core';
import { AngularFirestore, AngularFirestoreCollection, DocumentChangeAction } from '@angular/fire/firestore';
import { Expense } from '../model/Expense';
import { Observable, ReplaySubject, Subject, from } from 'rxjs';
import { map } from 'rxjs/operators';
import { AuthService } from '../core/services/auth.service';
@Injectable({
providedIn: 'root',
})
export class ExpenseService {
private dbPath = '/expenses';
expenseDetailEvent: EventEmitter<Expense> = new EventEmitter<Expense>();
expensesRef: AngularFirestoreCollection<Expense> = null;
expenses$: Observable<Expense[]>;
constructor(private db: AngularFirestore, auth: AuthService) {
auth.user$.subscribe(
user => {
this.expensesRef = this.db.collection<Expense>(this.dbPath, ref =>
ref.where('clientId', '==', user.uid)
);
this.expenses$ = this.expensesRef.snapshotChanges().pipe(
map(actions =>
actions.map(a => {
const data = a.payload.doc.data() as Expense;
const id = a.payload.doc.id;
return { id, ...data };
})
)
);
},
error => console.log(error)
);
}
createExpense(expense: Expense): Observable<any> {
return from(this.expensesRef.add(expense));
}
updateExpense(expense: Expense): Observable<any> {
return from(this.expensesRef.doc(expense.id).update(expense));
}
}
并且组件只是做
ngOnInit() {
this.expenseService.expenses$.subscribe(expenses => this.expenses = expenses);
}
我注意到在线上的所有示例都在组件上调用它,但我觉得数据库调用应该以与普通 http api 调用类似的方式在服务中
更新如果我像这样初始化服务
expenses$: Observable<Expense[]> = of([]);
所以当然应用程序不会崩溃,但如果我只是将代码拉到外面并使用静态 UID,我看不到任何数据......(当然 user.uid 与我粘贴的静态字符串相同)
这是更新的代码
constructor(private db: AngularFirestore, auth: AuthService) {
console.log('being here ,i see the data on screen using the static uid');
this.expensesRef = this.db.collection<Expense>(this.dbPath, ref =>
ref.where('clientId', '==', 'noYVScDtKfNB5aFqRkAJR7ghxio2')
);
this.expenses$ = this.expensesRef.snapshotChanges().pipe(
map(actions =>
actions.map(a => {
const data = a.payload.doc.data() as Expense;
const id = a.payload.doc.id;
return { id, ...data };
})
)
);
auth.user$.subscribe(
user => {
console.log('if inside here than it will not show any data on screen');
},
error => console.log(error)
);
}
解决方案
问题是expenses$
Observable 只有在发出某些东西之后才会被定义auth.user$
,因为那时就是它被分配的时候。
解决方案 1
您可以尝试ExpenseService
在更高级别组件的构造函数中注入服务,甚至可能是AppComponent
,以便ExpenseService
调用 的构造函数并expenses$
分配 Observable(您只需要注入它,无需任何方法调用或属性访问)。此时,当您加载组件时,应定义 Observable
解决方案 2expenses$
使用
手动创建 Observableof
然后订阅this.expensesRef.snapshotChanges()
您可以将值返回expenses$
就像是:
...
expensesSubject = new Subject<Expense[]>();
expenses$: from(expensesSubject);
constructor(private db: AngularFirestore, auth: AuthService) {
auth.user$.subscribe(
user => {
this.expensesRef = this.db.collection<Expense>(this.dbPath, ref =>
ref.where('clientId', '==', user.uid)
);
this.expensesRef.snapshotChanges().pipe(
map(actions =>
actions.map(a => {
const data = a.payload.doc.data() as Expense;
const id = a.payload.doc.id;
return { id, ...data };
})
)
).subscribe((whatever) => {
expensesSubject.next(whatever);
})
}
)
}
推荐阅读
- c# - 解析值时遇到错误意外字符:。路径'',第 1 行,位置 1
- c++ - 在 C++ Primer 第 5 版中使用自赋值检查重载“=”运算符 - 第 13.4 章
- schema.org - Schema.org 组织 URL 标记问题
- javascript - 将 S3 字节数组转换为 base64
- sql - 我正在尝试在 Teredata 中使用 OR 条件
- webrtc - 为什么我的 WebRTC 代码在没有指定 STUN/TURN 服务器 url 的情况下工作?
- vba - VBA - 尝试自动登录网站时出现错误 438
- python - 在 for 循环中添加数字列表
- qt - QRenderCapture 保存奇怪的截图
- python-3.x - 根据索引名称字符串操作删除列