angular - 尽管在构造函数中设置并正确订阅了Angular Observable undefined(使用firebase)
问题描述
我的组件错误:ERROR TypeError: "this.brandService.getCurrentBrand(...) is undefined"
问题是this.auth.currentUser.then()
BrandService 构造函数块内的代码在组件订阅它之前没有运行,因此组件出现未定义的错误。
我的组件订阅了我的 BrandService 中的“currentBrand” Observable:
private currentBrand: Brand;
ngOnInit(): void {
this.brandService.getCurrentBrand().subscribe((brand) => {
this.currentBrand = brand;
});
}
BrandService在构造函数中设置“currentBrand”,并使用 getCurrentBrand() 方法返回它:
private currentBrand: Observable<Brand>;
constructor(
private afs: AngularFirestore,
private auth: AngularFireAuth,
private userService: UserService
) {
this.brandsCollection = this.afs.collection('brands', (ref) =>
ref.orderBy('name', 'asc')
);
this.auth.currentUser.then((authUser) => {
console.log('this is logged prior to the undefined error');
this.userService.getUserByEmail(authUser.email).then((user) => {
console.log('for some reason, this is logged after the undefined error, need this to run prior to in order to eliminate the error');
this.currentBrand = this.getBrand(user.defaultBrandId);
});
});
}
getCurrentBrand(): Observable<Brand> {
return this.currentBrand;
}
getBrand(id: string): Observable<Brand> {
this.brandDoc = this.afs.doc<Brand>(`brands/${id}`);
this.brand = this.brandDoc.snapshotChanges().pipe(
map((action) => {
if (action.payload.exists === false) {
return null;
} else {
const data = action.payload.data() as Brand;
data.id = action.payload.id;
return data;
}
})
);
return this.brand;
}
我不确定我在这里做错了什么。我认为 BrandService 构造函数中的所有内容都应该在组件的 ngOnInit 之前运行,因此不应该发生这个未定义的错误。我正确地将代码放置在 .then() 方法中的构造函数中,该方法在解决 Promises 时执行。我只是似乎无法弄清楚这一点...
解决方案
你可以制作currentBrand
一个 RxJS BehaviorSubject
。这是混合 Promise 和 observables 的常见情况。我正在使用 RxJS将 Promisefrom
转换为 observables 并使用switchMap
运算符对其进行映射,以最终在方法中进行(可能是 HTTP)调用this.getBrand()
。
尝试以下
private currentBrand = new BehaviorSubject<Brand>(null);
constructor(
private afs: AngularFirestore,
private auth: AngularFireAuth,
private userService: UserService
) {
this.brandsCollection = this.afs.collection('brands', (ref) =>
ref.orderBy('name', 'asc')
);
from(this.auth.currentUser).pipe(
switchMap((authUser) => {
console.log('this is logged prior to the undefined error');
return from(this.userService.getUserByEmail(authUser.email)).pipe(
switchMap((user) => {
console.log('for some reason, this is logged after the undefined error, need this to run prior to in order to eliminate the error');
return this.getBrand(user.defaultBrandId);
})
)
})
).subscribe(
response => {
this.setCurrentBrand(response); // <-- push the response to `currentBrand` observable here
},
error => {
// handle error
}
);
}
getCurrentBrand(): Observable<Brand> {
return this.currentBrand.asObservable();
}
setCurrentBrand(brand: Brand) {
this.currentBrand.next(brand);
}
零件
ngOnInit(): void {
this.brandService.getCurrentBrand().subscribe((brand) => {
if (brand) {
this.currentBrand = brand;
}
});
}
推荐阅读
- ios - Flutter:该应用程序不是为 iOS 构建的
- azure - Azure DevOps 项目 SharePoint 门户:文档存储库
- firebase - 在应用启动时向 Firestore 提交离线数据
- python - 如何使用rtree,python在查询框(查询区域)中找到最近的点
- python - Python selenium - 选择子元素
- android-source - 瑞芯微AOSP ROM如何实现OTA更新?
- javascript - 使用 JavaScript/MomentJS 显示一致的时间,无论时区如何
- jquery - 是什么阻止了fancybox 在重新绘制页面后正确加载?
- javascript - 如何使用 JavaScript 创建具有多个可选参数的搜索?
- ios - 使用 Pulley 库的嵌入式视图控制器的 Nil IBOutlet