2

Here is my project layout:

enter image description here

Here is the user data service function that returns the user ID:

get uid(): BehaviorSubject<string> {
    const uidSubject: Subject<string> = new Subject<string>();
    this.afAuth.authState.subscribe((data) => {
      uidSubject.next(data.uid);
    });
    return uidSubject;
  }

Then here is the user tasks service that gets the tasks using the ID from the previous service:

  get tasks(): BehaviorSubject<string> {
    const tasksSubject: BehaviorSubject<string> = new BehaviorSubject<string>('no tasks available');
    this.afs.collection(`users/${this.uid}/tasks`).valueChanges().subscribe(tasks=> {
      if (tasks.length !== 0) {
        tasksSubject.next(tasks);
      }
    });
    return tasksSubject;
  }

I then subscribe in the App Component to get the data from the tasks service but the user ID is obviously undefined because the tasks function gets called before the uid function.

So how can make sure that the user data service gets the uid before the tasks service gets called?

halfer
  • 19,824
  • 17
  • 99
  • 186
Hamed Baatour
  • 6,664
  • 3
  • 35
  • 47

1 Answers1

1

I guess a solution is to use Observable's flatMap. Something like this (I rewrote your code, but I couldn't test it)

get uid(): BehaviorSubject<string> {
  const uidSubject: Subject<string> = new Subject<string>();
  return this.afAuth.authState
}

get tasks(uid): BehaviorSubject<string> {
  const tasksSubject: BehaviorSubject<string> = new BehaviorSubject<string>('no tasks available');
  return this.afs.collection(`users/${uid}/tasks`).valueChanges()
}

caller() {
  this.uid().flatMap( data => {
    //pass data as parameter, will be the id
    return this.tasks(data)
  })
  .subscribe( tasks => {
     //do what you need
  })
}

there is this good thread about this.

Christian Benseler
  • 7,907
  • 8
  • 40
  • 71
  • thanks, however, I really wanted to avoid importing both of the services and cluttering the app component with a lot of logic so I can structure my project components for just displaying the data(for testing purposes). So do you think that splitting up my logic into multiple services was a bad idea and I just have to combine them into one to avoid the problem? – Hamed Baatour Oct 17 '17 at 16:29
  • I don't see the point of avoid importing/injecting multiple services. A service should have "specialized" methods so it would be easier to decouple and reuse them. You can, of couse, write just one service with a lot of logic, but you will be missing the point of those benefits. Anyway, this doesn't matter for this case you mentioned, that you need to call methods (that return Observables) in sequence. flatMap will help you. – Christian Benseler Oct 17 '17 at 16:33