Search code examples
angularngrx-storerxjs-observables

Return Observable from ngrx store pipe selector


I have a ngrx store selector:

export const selectActivePracticeUsersListSnapshot = pipe(
  select(selectPracticeUsersList),
  filter((users) => !!users),
  take(1),
  map((users) => users.filter((user) => user.active))
);

I have a service that is injected into multiple components that contains the following method:

public getTeamMembersWithAccess(permission: string): string[] {
  let flagAvatars: string[];
  this.store.dispatch(loadUsers());
  this.store.pipe(selectActivePracticeUsersListSnapshot).subscribe((activePracticeUsers) => {
    flagAvatars = activePracticeUsers.reduce((teamMembers, activeUser) => {
      if (!!activeUser.permissions[permission]) {
        const { firstName, lastName } = activeUser;
        return [...teamMembers, `${firstName} ${lastName}`];
      }
      return teamMembers;
    }, []);
  });
  return flagAvatars;
}

I call this from my component thusly:

constructor(private helperService: HelperService) {
  const flagAvatars = this.helperService.getTeamMembersWithAccess('AdminPage');
}

My problem is that the service method returns undefined because of the let flagAvatars: string[]; before the subscription to the store selector returns as it is waiting for the dispatch of loadUsers() to complete. I know I need to change the getTeamMembersWithAccess() method to return an Observable<string[]> somehow, but I'm not sure how to write this. I've tried multiple things but can't get it right. Pretty sure I need to use a map instead of a subscribe, but just can't figure out how to write that.


Solution

  • You're completely right with your statement, I will assist you in making it concrete.

    Try this:

    Service:

    import { map } from 'rxjs/operators';
    ......
    public getTeamMembersWithAccess(permission: string): Observable<string[]> {
      this.store.dispatch(loadUsers());
      this.store.pipe(selectActivePracticeUsersListSnapshot).pipe(
       map((activePracticeUsers) => {
        // flagAvatars equals this, so let's just return it right away in the map
        return activePracticeUsers.reduce((teamMembers, activeUser) => {
          if (!!activeUser.permissions[permission]) {
            const { firstName, lastName } = activeUser;
            return [...teamMembers, `${firstName} ${lastName}`];
          }
          return teamMembers;
        }, []);
       });
      )
    }
    

    To consume it:

    this.helperService.getTeamMembersWithAccess('AdminPage').subscribe(data => {
      console.log(data);
    });