jmo31
jmo31

Reputation: 21

Method is not returning the correct value passed from observable subscription

I'm trying to validate from an API (Angular's in-memory API) that a user exists given a username. The function checkUsernameExists(username) returns an Observable<boolean> based on whether the API returns undefined or a user object. I'm having an issue that regardless of the username (existing or not existing) it always returns false. I know that getUser() functions correctly as it returns undefined when a user doesn't exists and the user object when it does.

Preferably would only like to adjust the checkUsernameExists function if possible. This function is used for a (working) async validator. I've looked up all over how to solve this type of thing but can't find anything that isn't deprecated or fits what I need in order for it work properly.

  usersUrl = '/api/users';

  constructor(private http: HttpClient) {}

  users = this.http.get<User[]>(this.usersUrl).pipe(shareReplay());

  // gets a user object when subscribed to
  getUser(username: string): Observable<User | undefined> {
    return this.users.pipe(
      take(1),
      map((users: User[]) => {
        return users.find((user) => user.username === username);
      })
    );
  }

  // check if user exists
  checkUsernameExists(username: string): Observable<boolean> {
    var userValid = false;

    this.getUser('[email protected]')
      .pipe(take(1)).subscribe(
        result => {
          if (result === undefined) {
            console.log('result: ', result);
            return (userValid = false);
          } else {
            console.log('result: ', result);
            return (userValid = true);
          }
        }
      );

    console.log(userValid)  // no matter the username, the value is always the same as its initialization (false)

    return of(userValid);
  }

Upvotes: 0

Views: 258

Answers (2)

Lyoid Lopes
Lyoid Lopes

Reputation: 1

/* How about you use promise */

checkUsernameExists(username: string): Promise<any> {
        return new Promise<any>((resolve, reject) => {
          this.getUser('[email protected]')
            .subscribe(
              async (result: any) => {
                if(result) 
                {            
                  console.log('result: ', result);
                    resolve(result)         
                }
                else if(result && result.IsError)  
                {
                  console.log('result: ', result);
                  reject(result.Error)  
                }
            },
            (err) => {
              reject(err)   
            });        
        });
      }

/* To Call this Method => Do what you want to do with the result */

 await checkUsernameExists("Your_Username").then((res) => {
    console.log(res)
    }, (err) => {
    console.log(err)
    })

Upvotes: 0

Edward
Edward

Reputation: 1126

your order of operations is the the problem in checkUserNameExists method

you must wait for the observable to complete. but your code is making call to an observable this.getUser and then immediately returning return of(userValid).

since the observable has not completed, the vale of userValid is stil the default false. which is the behavior you described

Update your method to

checkUsernameExists(username: string): Observable<boolean> {
    return this.getUser('[email protected]').pipe(
      .map( (result: any) => {
        if (result === undefined) {
          console.log('result: ', result);
          return (userValid = false);
        } else {
          console.log('result: ', result);
          return (userValid = true);
        }
     })
  );

}

this ensures that the userValid is only returned when the observable has completed.

and is also removes the need for double susbscription

Upvotes: 2

Related Questions