'Why is my Firebase/AngularFire query returning an Observable instead of data?

My other Firebase queries are returning data but a query I wrote today returns an Observable instead of data. What does that mean? Why doesn't it return data? Is an Observable like an unfulfilled promise, meaning that we're waiting for the database to send the data?

import { Component, Input, Inject, } from '@angular/core';
import { Observable } from 'rxjs';

// Firebase
import { AngularFirestore, AngularFirestoreDocument } from '@angular/fire/compat/firestore';

// types
import { L2Language } from '../../services/home-toolbar/home-toolbar.service';
import { LearningModes } from '../../services/home-toolbar/home-toolbar.service';

// services
import { HeaderToolbarService } from '../../services/header-toolbar/header-toolbar.service';

export interface ClipInMovieWatching { clip: number; };

@Component({
  selector: 'app-videos-vocabulary',
  templateUrl: './videos-vocabulary.component.html',
  styleUrls: ['./videos-vocabulary.component.css']
})
export class VideosVocabularyComponent {
  userUid: string | undefined = undefined;

  private clipInMovieWatchingDoc: AngularFirestoreDocument<ClipInMovieWatching>;
  clipInMovieWatching: Observable<ClipInMovieWatching | undefined>;

  constructor(
    private firestore: AngularFirestore,
    @Inject(HeaderToolbarService) private headerToolbarService: HeaderToolbarService
  ) { }

  videoSelector() {
    this.headerToolbarService.getUser().subscribe((user: any) => {
      this.userUid = user.uid;
      console.log(this.userUid); // √ this works
      this.clipInMovieWatchingDoc = firestore.collection('Users').doc(this.userUid).collection('English').doc('Videos').collection('Walker_Climbs_a_Tree').doc<ClipInMovieWatching>('Clip_In_Movie_Watching');
      this.clipInMovieWatching = this.clipInMovieWatchingDoc.valueChanges();
      console.log(this.clipInMovieWatching);
      console.log(this.clipInMovieWatching.clip);

    })
  }

}

Here's my Firestore database:

enter image description here

I'm expecting

console.log(this.clipInMovieWatching);

to return an object but returns an Observable.

I'm expecting

console.log(this.clipInMovieWatching.clip);

to return 5 but I get an error

Property 'clip' does not exist on type 'Observable<ClipInMovieWatching | undefined>'.

Do I need to put a ? somewhere (because no property exists on the type undefined)?

I made an interface for the document ClipInMovieWatching which has only a single property clip.

I brought the userUid in from the component with the Firebase Auth methods.

I make two variables clipInMovieWatchingDoc and clipInMovieWatching.

When the method videoSelector() is called it gets the userUid and then calls Firestore. The Firestore path is deeply nested but I've checked this a million times, and I tried using a shorter path to another document and got the same result.



Solution 1:[1]

I got it working.

In the view I put this:

<div>
    Clip: {{ (clipInMovieWatching | async)?.clip }}
</div>

The value displays in the view. This shows that the Firestore query is working.

To use the value in the component controller I found the answer in a blog post about ValueChanges. This is an Angular event, not a Firebase feature.

I changed these lines:

console.log(this.clipInMovieWatching);
console.log(this.clipInMovieWatching.clip);

to

 this.clipInMovieWatching.subscribe(x => {
        console.log(x?.clip);
      })

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1