skip to Main Content

I am trying to use this service getTodaysRoute() where I figure out what is today’s route node key using .equalTo and from what I understand then I have to use this .on function snapshot from which then I can finally get the key after that I use this key to get data as an observable. The problem happens that the code inside .on function gets executed last and the first time page load my todaysroutekey is undefined. How can I avoid a situation like this?

getTodaysRoute(): Observable<Location[]> {
    const date = new Date().toISOString().replace(/T.*/, '');
    const userdate = `${this.useremail}${date}`;
    let todaysroutekey;
     this.db.database 
      .ref()
      .child('routes')
      .orderByChild('user_date')
      .equalTo(userdate)
      .on('child_added', function ( snapshot) {
       
        todaysroutekey =  snapshot.key;

      });
     
    console.log(todaysroutekey);
    return this.db
      .list(`${this.routesUrl}/${todaysroutekey}/locations`)
      .snapshotChanges()
      .pipe(
        map((locations) =>
          locations.map(
            (location) =>
              ({
                key: location.payload.key,
                ...(location.payload.val() as {}),
              } as unknown as Location)
          )
        )
      );
  }

And this is my component code

  routeLocations: any[];

  constructor(private firebase: FirebaseService) { }

  ngOnInit(): void {
    this.firebase.getTodaysRoute().subscribe((value) => {
      this.routeLocations = value;
    });
  }

2

Answers


  1. Chosen as BEST ANSWER

    After 2 weeks of trying just about everything this was the solution:

    async getTodaysRoute(): Promise<Observable<Location[]>> {
    const date = new Date().toISOString().replace(/T.*/, '');
    const userdate = `${this.useremail}${date}`;
    let todaysroutekey;
    await this.db.database
      .ref()
      .child('routes')
      .orderByChild('user_date')
      .equalTo(userdate)
      .once('child_added', function (snapshot) {
        todaysroutekey = snapshot.key;
      });
    
    return this.db
      .list(`${this.routesUrl}/${todaysroutekey}/locations`)
      .snapshotChanges()
      .pipe(
        map((locations) =>
          locations.map(
            (location) =>
              ({
                key: location.payload.key,
                ...(location.payload.val() as {}),
              } as unknown as Location)
          )
        )
      );
    

    }

    this.firebase.getTodaysRoute().then(
      (event) =>
        event.subscribe(
          (value: any) =>
            (this.routeLocations = value.sort((a, b) => a.id - b.id))
        )
    );
    

  2. This is the expected behavior, as on (like most modern cloud APIs) is an asynchronous operation.

    One way to handle this is to nest the second query inside the on callback of the first one:

    const date = new Date().toISOString().replace(/T.*/, '');
    const userdate = `${this.useremail}${date}`;
    let todaysroutekey;
     this.db.database 
      .ref()
      .child('routes')
      .orderByChild('user_date')
      .equalTo(userdate)
      .on('child_added', function ( snapshot) {       
        todaysroutekey =  snapshot.key;
    
        console.log(todaysroutekey);
    
        return this.db
          .list(`${this.routesUrl}/${todaysroutekey}/locations`)
          .snapshotChanges()
          .pipe(
            map((locations) =>
              locations.map(
                (location) =>
                  ({
                    key: location.payload.key,
                    ...(location.payload.val() as {}),
                  } as unknown as Location)
              )
            )
          );
      });
    

    You won’t be able to return the Observable in that case though. I recommend looking into using once (instead of on) and checking out async/await for that.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search