我的组件错误: 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;
});
}
The 品牌服务 是在构造函数中设置 "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
a RxJS BehaviorSubject
. 这是一个常见的承诺和观测值混合的情况。我使用的是RxJS from
将承诺转换为观测值,并使用 switchMap
操作员,以最终在 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;
}
});
}
所以你所面临的问题是因为你的代码是异步执行的。我已经试着解释了这个问题,在你的组件内部,你试图在ngoninit方法中获取它的值,就像下面给出的private currentBrand::。
//When the instance of ur service get created this thing is undefined
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 is async function which will take some time
this.auth.currentUser.then((authUser) => {
console.log('this is logged prior to the undefined error');
// this again is async operation
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');
// ONCE ALL THE ASYNC OPERATION ARE DONE YOU ARE ASSINGING THE VALUE HERE
this.currentBrand = this.getBrand(user.defaultBrandId);
});
});
}
// SO it will take some time to set value
//Till that time currentBrand will be undefined
getCurrentBrand(): Observable<Brand> {
return this.currentBrand;
}
在你的组件内部,你试图在ngoninit方法中获得它的值,就像下面给出的private currentBrand: Brand;
ngOnInit(): void {
this.brandService.getCurrentBrand().subscribe((brand) => {
this.currentBrand = brand;
});
}
this.brandService.getCurrentBrand() /
这个值在你所有的承诺得到解决之前都是未定义的。
我希望你明白了这个问题。现在的解决方法是将currentBrand作为行为主体,然后在内部承诺上做下一步。
currentBrand : =new BehaviourSubject(initial value);
在你的承诺里面,这样做。
currentBrand.next('value you get from ur promise' )