首页 > 解决方案 > double combineLatest 不发出更新

问题描述

在我的项目中,人们创建、加入、添加书签或组织了一些活动。我已经阅读了很多这些问题。但是大部分代码都不那么复杂,或者人们忘记订阅了......

我想获取某个时间段内的所有活动,然后添加创建者信息(名称、图像等)并添加布尔值(如果检索这些活动的用户已加入/添加书签/组织了此活动)。我之前使用的代码将提供实时更新(例如,我通过将我的 userId 添加到参与者数组中来加入活动,并且 activity.joined 将更新为 true)。

以前的代码:

public getActivities(user: UserProfileModel): Observable<Array<ActivityModel>> {
    const now: number = moment().startOf('day').unix();
    const later: number = moment().startOf('day').add(30, 'day').unix();
    return this.afs.collection<ActivityModel>(`cities/${user.city.id}/activities`, ref => ref
        .where('datetime', '>=', now)
        .where('datetime', '<=', later))
        .valueChanges({ idField: 'id' })
        .pipe(
            map(activities => activities.map(activity => {
                const bookmarked = activity.bookmarkers ? activity.bookmarkers.includes(user.uid) : false;
                const joined = activity.participants ? activity.participants.includes(user.uid) : false;
                const organized = activity.organizers ? activity.organizers.includes(user.uid) : false;
                return { bookmarked, joined, organized, ...activity } as ActivityModel;
        }))
    );
}

我想将创建者添加为可观察对象,以便显示他们的名称或个人资料图片的最新更改。但是随着这个代码的改变,我的 getActivities 不再发出任何更新......

我的新代码:

public getActivities(user: UserProfileModel): Observable<Array<CombinedActivityCreatorModel>> {
    const now: number = moment().startOf('day').unix();
    const later: number = moment().startOf('day').add(30, 'day').unix();
    return this.afs.collection<ActivityModel>(`cities/${user.city.id}/activities`, ref => ref
        .where('datetime', '>=', now)
        .where('datetime', '<=', later))
        .valueChanges({ idField: 'id' })
        .pipe(
            concatMap(activities => {
                const completeActivityData = activities.map(activity => {
                    const activityCreator: Observable<UserProfileModel> = this.getCreator(activity.creator);
                    const bookmarked = activity.bookmarkers ? activity.bookmarkers.includes(user.uid) : false;
                    const joined = activity.participants ? activity.participants.includes(user.uid) : false;
                    const organized = activity.organizers ? activity.organizers.includes(user.uid) : false;
                    return combineLatest([
                        of({ bookmarked, joined, organized, ...activity }),
                        activityCreator
                    ]).pipe(
                        map(([activityData, creatorObject]: [ActivityModel, UserProfileModel]) => {
                            return {
                                 ...activityData,
                                 creatorObject: creatorObject
                            } as CombinedActivityCreatorModel;
                        })
                    );
                });
            return combineLatest(completeActivityData);
        })
    );
}

代码变得有点复杂,我自己看不到解决方案。有人可以提供一些帮助吗?

标签: javascriptfirebasegoogle-cloud-firestorerxjsangularfire2

解决方案


看起来其中一个activityCreator没有发出值,combineLatest 要求所有可观察对象至少发出一次。

我建议您调试activityCreator行为方式。如果它不发射很好,你有两个选择:startWith为初始发射设置一个值,或者defaultIfEmpty,如果流将在没有任何发射的情况下关闭,它就会发射。

activityCreator = this.getCreator(activity.creator).pipe(
  // startWith(null), // for example if you want to trigger combineLatest.
  // defaultIfEmpty(null), // in case of an empty stream.
);

另一件事是concatMap它需要一个 observable 来完成,然后它才会切换到下一个,也许mergeMap或者switchMap更适合这里。

尝试下面的代码并将其输出添加到注释中。谢谢。

                        const activityCreator: Observable<UserProfileModel> = this.getCreator(activity.creator).pipe(
                            tap(
                                () => console.log('getCreator:emit'),
                                () => console.log('getCreator:error'),
                                () => console.log('getCreator:completed'),
                            ),
                        );

推荐阅读