ervin
ervin

Reputation: 549

Angular2: getting service's property value before call a method

I have implemented FireDatabaseService as @Injectable({ providedIn: 'root' }) in my app. It of course works with DI. In this service I need Firebase UID from another service, but this UID is being fetched with subscription. Because of this methods that need UID are called before this UID is available. I have no idea how to get UID before getUserGroup() is called. Here is my service:

...
@Injectable({ providedIn: 'root' })
export class FireDatabaseService {
  uid: string;

  constructor(
    private readonly db: AngularFireDatabase,
    private readonly authService: AuthService
  ) {
    this.authService.authState.subscribe(
      (state: firebase.User) => this.uid = state.uid
    );
  }

  getUserGroup(): Observable<string> {
    return this.db
      .object(`users/${this.uid}`)
      .valueChanges()
      .pipe(map((userData: any) => userData?.group as string));
  ...
  }

Calling fireDatabaseService.getUserGroup() goes with uid = ''. Is there any possibility to fix it? Thanks for help.

Upvotes: 0

Views: 97

Answers (2)

BizzyBob
BizzyBob

Reputation: 14740

I suggest that you do not subscribe at all in your service, but rather define your uid and userGroup as observables. The userGroup$ can be defined from the uid$ observable:

@Injectable({ providedIn: 'root' })
export class FireDatabaseService {
  uid$ = this.authService.authState.pipe(
    map(state => state.uid)
  );

  userGroup$ = this.uid$.pipe(
    switchMap(uid => this.db.object(`users/${uid}`).valueChanges())
    map(userData => userData?.group as string)
  );

  constructor(
    private readonly db: AngularFireDatabase,
    private readonly authService: AuthService
  ) { }
}

Observables are lazy, so it is not necessary to wrap them as functions. They don't emit a value until .subscribe() is called on them.

Upvotes: 0

peinearydevelopment
peinearydevelopment

Reputation: 11474

It is a little unclear to me what your requirements are. The easiest way to accomplish what I think you are asking would be the following:

...
@Injectable({ providedIn: 'root' })
export class FireDatabaseService {
  constructor(
    private readonly db: AngularFireDatabase,
    private readonly authService: AuthService
  ) {
  }

  getUserGroup(): Observable<string> {
    return this.authService
               .authState
               .pipe(
                   switchMap((state: firebase.User) => 
                       this.db
                           .object(`users/${state.uid}`)
                           .valueChanges()
                   ),
                   map((userData: any) => userData?.group as string)
               );
  ...
  }

Everytime getUserGroup is called, there would be another call to the authService. That might be undesireable, but that could be mitigated through the use of shareReplay(1) or through another strategy depending on the functionality you are expecting.

Upvotes: 2

Related Questions