【问题标题】:double combineLatest doesn't emit updatedouble combineLatest 不发出更新
【发布时间】:2020-05-27 12:48:55
【问题描述】:

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

我想获取某个时间段内的所有活动,然后添加创建者信息(姓名、图像等)并添加布尔值(如果检索这些活动的用户已加入/添加书签/组织了此活动)。我之前使用的代码会提供实时更新(例如,我通过将我的 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);
        })
    );
}

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

【问题讨论】:

  • this.getCreator 返回的 observable 是否完整?
  • 我认为它完成了。请参阅下面我对 satanTime 的回答。

标签: javascript firebase google-cloud-firestore rxjs angularfire2


【解决方案1】:

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

我建议您调试 activityCreator 的行为方式。 如果它不发射没问题,您有 2 个选项: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 才能完成,然后才切换到下一个,也许 mergeMapswitchMap 更适合这里。

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

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

【讨论】:

  • 感谢您的回复。我已将行更改为: const activityCreator: Observable = this.getCreator(activity.creator).pipe( startWith(null), // 例如如果你想触发 combineLatest.defaultIfEmpty(null), //在空流的情况下。 tap((creator) => console.log("get creator", creator)) ) 在控制台中,我首先得到 null,然后是 creatorObject。所以这看起来很好,对吧?
  • 是的。 startWith 总是作为第一个即时值发出。这就是为什么我还建议defaultIfEmpty - 它在开始时不会发出,但如果流在没有任何发出的情况下关闭则发出。取决于什么更适合您的要求。
  • 我认为我的问题有点不清楚。我已经添加了我的旧代码。该代码确实在活动数组中发出更新。新代码没有。你认为我的新代码中有什么会破坏这个?我可以在保留可观察的创建者(用户)信息的同时修复它吗?
  • 知道了,我会尽快检查并通知您。
  • 您可以检查答案的第二部分吗? concatMap 是故意添加的,能解释一下吗?
猜你喜欢
  • 2018-09-29
  • 2019-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多