Home > Software design >  Method is provided an array of usernames and HTTP request for each --> returns observable array o
Method is provided an array of usernames and HTTP request for each --> returns observable array o

Time:09-21

I'm trying to get a array of objects when provided a (non-observable) array of usernames (string[]). I would like to have a method that is able to get each user object via getUser(username) (HTTP GET request from Angular in-memory web API) for each provided username string and ultimately return an observable array of the user objects. And then be able to get the array from the observable array. I've been juggling around different ways of trying to figure this out but have been struggling.

Preferably would like to avoid using promises if possible.

Attempted method:

usernamesToUserObjects(usernames: string[]): User[] {
  var members: User[] = [];

  for (let username of usernames) {
    if (username.trim() === '') {
      continue;
    } else {
      this.userService.getUser(username.trim())
       .pipe(
          map((user: User[] | undefined) => {
            if (user !== undefined) {
              console.log(`(debug) ${user.username} was found!`);
              members.push(user);
            }
          })
        );
    }
  }

  // I understand that the requests aren't finishing before continuing to the next but need help on making that occur
  console.log(`(debug) User objects are : ${members}`);
  return members;
}

UserService methods used: (work fine)

usersUrl = '/api/users';

constructor(private http: HttpClient) {}

// have to grab users this way in order to get them from angular web api (can only get by 'id' not by a 'username')
users = this.http
  .get<IUser[]>(this.usersUrl)
  .pipe(retry(2), catchError(this.handleError('getUsers()', [])));

// check if user is in users
getUser(username: string): Observable<IUser | undefined> {
  return this.users.pipe(
    take(1),
    map((users: IUser[]) => {
      return users.find((user) => user.username === username);
    })
  );
}

How could I return an Observable<User[]> and then get User[] from that observable?

CodePudding user response:

The function can't return an User[] because fetching a User seems to be an asynchronous operation. So you can either return a Promise or an Observable. I would go with the Observable approach.

To "await" all Observables, I would use forkJoin as an equivalent to Promise.all()

usernamesToUserObjects(usernames: string[]): Observable<User[]> {
  return forkJoin(
    usernames
      .filter(username => username.trim() !== '')
      .map(username => this.userService.getUser(username.trim()))
  ).pipe(
    map(users => users.filter(user => user !== undefined))
  )
}

Playground

  • Related