Anand
Anand

Reputation: 1699

How to make an observable from another observable?

I have an observable

  public get users(): Observable<User[]> {
    return this.userData.asObservable();
  }

I want to create another observable from this

  public get usedRoles(): Observable<Roles[]> {
    // create the observable to get all the roles from all users
  }

Where each User has an attribute roles: Array<Role>

I tried flatMap however getting stuck with the getting the right structure.

  public get usedRoles(): Observable<Role[]> {
    return this.users.flatMap(users => users.map(u => u.roles));
  }

But this is just giving me arrays of roles separately for each user as shown by this this.usedRoles.subscribe(roles => console.log(roles));

I want a single array with the distinct list of roles used by all users.

Thanks so much for help!

Upvotes: 1

Views: 162

Answers (2)

Fateh Mohamed
Fateh Mohamed

Reputation: 21387

try this

  public get usedRoles(): Observable<Role[]> {
    return this.users.flatMap((users) => {
      const roles = [];
      users.forEach((user) => {
        // roles = roles.concat(user.roles);
        user.roles.forEach(r => {
          if (!roles.some(role => role.id === r.id)) {
            roles.push(r);
          }
        });
      });
     return Observable.of(roles);
    });
  }

Upvotes: 1

Tomasz Kula
Tomasz Kula

Reputation: 16847

If you are mapping a value into another value you can use the regular map operator.

flatMap should be when the result returned by your projection function is another observable.

import { map } from 'rxjs/operators';
import { Observable } from 'rxjs/Observable';

getUserRoles(): Observable<Role[]> {
  return this.users.pipe(
    map(users => users.reduce((roles, user) => [...roles, ...user.roles], [])),
    map(arr => [...new Set(arr)])
  )
}

Upvotes: 0

Related Questions