0

I'd like, very much like in ngrx's selector definition, where you're able to plug a number of observables and have a projection function to return something.

Example

export const selectCommunityByRouteId = createSelector(
  selectRouteId,
  communitySelectors.selectEntities,
  (id, communities) => {
    if (id) {
      return communities.find(c => c.id === id);
    }
  }
);

^There is a selectRouteId and communitySelectors.selectEntities, 2 observable streams and a projection function that takes both inputs and returns something.

The below code is in my component. Essentially what I'm doing is determining if the owner of a community is the same that is visiting this community and if it is, set the admin only menu items to be seen.

Current

    this.community$.pipe(
      takeUntil(this.ngDestroyed$),
      switchMap(community => this.store.select(selectProfileByID(community && community.owner_id))),
    ).subscribe(profile => {
      if (profile) {
        const claims = this.oAuthService.getIdentityClaims();
        if (claims) {
          // @ts-ignore
          const sub = claims.sub;
          if (sub === profile.subject_id) {
            this.store.dispatch(setDrawerAdminNavigationItems({items: [
                {title: 'New Forum', route: ['/new/forum']}
              ]}));
          }
        }
      } else {
        this.store.dispatch(setDrawerAdminNavigationItems({items: undefined}));
      }
    });
  }

However now I'm 2 levels deeper in the nest and in a Community > Container > Forum relationship, I'm trying to give the owner the possibility to create a new forum. For this however I need to know the id of the Container I'm currently viewing. I have a

    this.container$ = this.store.select(selectContainerByRouteId);

this is not the issue. This issue is, I need to access the information coming from this selector/observable. So, in my subscribe I need to have not just

this.store.select(selectProfileByID(community && community.owner_id)

but also

this.container$
// or
this.store.select(selectContainerByRouteId)

so I have something like

.subscribe([profile, container] => {
// do something with that
});

or, more elaborate

Desired:

    this.community$.pipe(
      takeUntil(this.ngDestroyed$),
      switchMap(community => this.store.select(selectProfileByID(community && community.owner_id))),
    ).subscribe([profile, container] => {
      if (profile) {
        const CONTAINER_ID_HERE = container.id;
        const claims = this.oAuthService.getIdentityClaims();
        if (claims) {
          // @ts-ignore
          const sub = claims.sub;
          if (sub === profile.subject_id) {
            this.store.dispatch(setDrawerAdminNavigationItems({items: [
                {title: 'New Forum', route: ['/new/forum', CONTAINER_ID_HERE]}
              ]}));
          }
        }
      } else {
        this.store.dispatch(setDrawerAdminNavigationItems({items: undefined}));
      }
    });
  }

I know there's forkJoin, but this just combines all streams into a single one.

What I'm looking for is a way to take data from multiple streams and pass it to the next function. I believe combineLatest should do it.

What would the function have to look like with combineLatest? Could I still use switchMap? Can I even pass it in a pipe?

  • You managed to answer your own question at the same moment you posted it, that's impressive. – YounesM Feb 28 '20 at 16:35
  • Yeah I didn't want to throw it away, maybe someone will benefit from it. It happens so often, you write your problem down and then you have a wall of text and you solve it. But all the time and effort is wasted when you delete what you've written. Luckily there's the option to answer your own question when you submit the form. –  Feb 28 '20 at 16:40

1 Answers1

1

I managed to solve it myself, however I'm getting a deprecation warning about combineLatest. I found a closed github issue about combineLatest being deprecated, and also a Stackoverflow question.

In any case this is my currently working solution

    this.community$.pipe(
      takeUntil(this.ngDestroyed$),
      switchMap(community => {
        return combineLatest(this.store.select(selectProfileByID(community && community.owner_id)), this.container$);
      }),
    ).subscribe(([profile, container]) => {
      if ((profile) && (container)) {
        const claims = this.oAuthService.getIdentityClaims();
        if (claims) {
          // @ts-ignore
          const sub = claims.sub;
          if (sub === profile.subject_id) {
            this.store.dispatch(setDrawerAdminNavigationItems({
              items: [
                {title: 'New Forum', route: ['/new/forum', container.id]}
              ]
            }));
          }
        }
      } else {
        this.store.dispatch(setDrawerAdminNavigationItems({items: undefined}));
      }
    });
  • 1
    `combineLatest` is still supported, but not with multiple arguments, now `combineLatest` takes a single array as an argument. Just wrap your arguments in an array and you will get rid of the deprecation warning. – Wilt Feb 29 '20 at 07:40
  • Thank you. The commit that does this: https://github.com/reactivex/rxjs/commit/6661c79 –  Mar 01 '20 at 13:39