我需要运行一个带有2个参数的方法,每个参数都是通过某种形式的订阅函数获得的。第一个是从angular的页面路由通过url获得的集合。第二个是文档,这是Firebase的Firestore文档。
export class FirebaseDocument implements OnInit {
collection: string;
dokument: any;
//== CONSTRUCTORS
constructor(
private route: ActivatedRoute,
private _db: AngularFirestore
) {}
//== Initialize
ngOnInit() {
console.log("__loading page component");
this.route.params.subscribe(params => {
this.collection = params["collection"];
});
console.log(this.collection);//collection populated correctly
//load the document from AngularFirestore
console.log("loading the document from firebase");
let itemsCollection = this._db.collection(url).valueChanges();
//subscribe to get the dok of the first document in the collection
itemsCollection.subscribe(docArr => {
this.dokument = docArr[0];
console.log(this.dokument);//dokument is populated
});
console.log(this.dokument);//dokument is undefined
this.doMultiParameterMethod(this.collection, this.dokument);
}
}
this.collection填充得很好; this.dokument仅填充在subscription方法内部
我需要在下一行运行时填充它。 console.log(this.dokument);
这让我很困惑,因为2个订阅方法使用了基本上相同的代码,但是它们的行为方式不同。
答案 0 :(得分:0)
有时订阅可以是同步的。当Observable
是ReplaySubject
,BehaviorSubject
或具有Observable
管道的shareReplay()
时,就会发生这种情况。 (可能还有其他选择。
这将使可观察的对象立即在订阅时触发。但是,您永远不要指望这种行为,并且始终在订阅中继续。。或者使用诸如mergeMap之类的管道并创建其他可观察对象,您可以使用async
管道在模板中对其进行访问。
以您为例。 this.route.params
显然是一个“正在重放”的可观察对象,您可以在订阅后从中获得最新值。否则,您将不得不等待参数再次更改,直到获得值为止。
您的数据库调用无法返回立即响应,因为它本质上是网络请求。
在示例代码中,您可以对其进行更新,并在模板中使用async
管道
export class FirebaseDocument implements OnInit {
readonly collection$: Observable<string> = this.route.params.pipe(
map((params) => params.collection)
);
readonly doc$: Observable<any[]> = this.db.collection(this.url).valueChanges().pipe(
shareReplay({ refCount: true, bufferSize: 1 })
);
constructor(private route: ActivatedRoute, private db: AngularFirestore) {}
ngOnInit() {
// don't forget to unsubscribe
combineLatest([
this.collection$,
this.doc$
]).subscribe((collection, document) => {
this.doMultiParameterMethod(collection, document);
});
}
}
答案 1 :(得分:0)
也许您应该将“可观察到的”作为一个承诺,具体如下:
export class FirebaseDocument implements OnInit {
collection: string;
dokument: any;
//== CONSTRUCTORS
constructor(
private route: ActivatedRoute,
private _db: AngularFirestore
) {}
//== Initialize
ngOnInit() {
console.log("__loading page component");
this.route.params.subscribe(params => {
this.collection = params["collection"];
});
console.log(this.collection); //collection populated correctly
this.getDokument().then(docArr => {
this.dokument = docArr[0];
this.doMultiParameterMethod(this.collection, this.dokument);
});
}
getDokument(): Promise<any> {
let itemsCollection = this._db.collection(url).valueChanges();
return new Promise((resolve, reject) => {
itemsCollection.subscribe((response: any) => {
resolve(response);
}, reject);
});
}
}