There is a fundamental unknowable regarding timing that is baked into this code. getPosts is returning a service property, yet that service property is assigned to in a subscription. There is no easy way for getPosts to know, yet alone do anything with the knowledge about, when that assignment is going to occur.
I painted myself into corners like this many times, and eventually settled on the following rule, which in addition to making for (IMHO) clearer code, makes it much harder to step on such rakes:
All code that interacts with futures should either produce one or consume one, but never try to do both things.
A related rule:
The first word of a future-producing function should generally be
return.
If you haven’t seen this taxonomy of future-producers before, check it out. Based on its name and what it seems to be trying to do, loadPosts is in a tough spot. It’s really a category C, but it’s written like a category A. In fact, loadPosts and getPosts can’t really be disentangled, so I would combine them, and along the way totally get rid of all the instance properties in the service. There are ways to preserve them so that they make more sense, but for now I think things will be clearer if we can design away any potential sources of stale data.
I’m also going to dumb down your User class for philosophical reasons that can be discussed later if you care, but aren’t particularly germane here. Instead of the user itself generating followed groups, the service is going to do that given a POD User.
followedGroups(user: User): Observable<Group[]> {
}
postsForUser(user: User): Observable<Post[]> {
return this.followedGroups(user).pipe(
switchMap(groups => this.afs.collection<Post>('announcements', ref => ref.where('gid', 'in', groups).snapshotChanges()),
map(actions => actions.map(a => {
const data = a.payload.doc.data();
const id = a.payload.doc.id;
return { id, ...data };
})));
}