Jie Hart
Jie Hart

Reputation: 909

how to subscribe to Firestore observable within a service. Angular 7

I have made many attempts to create an Angular 7 Service that will return an observable from Firestore but the latest version returns no data (the best result so far); I used Angularfire2 because it is supposed to be designed for observables and easier to use.

My Service is data4eatery.ts:

import { Injectable } from '@angular/core';
import { AngularFirestore, AngularFirestoreCollection } from 'angularfire2/firestore';
import { Observable } from 'rxjs';

import { IeTables } from './../components/models/eateries-model';

@Injectable({
  providedIn: 'root'
})
export class Data4eateryService {
  tablesCollection: AngularFirestoreCollection<IeTables>;
  tables: Observable<IeTables[]>;

  constructor(private afs: AngularFirestore) { }

  getTables() {
    this.tablesCollection = this.afs.
      collection('eEatery').doc('J3XTNqSWGzmU4261BDHD'). //hard coded for testing
      collection('eTable');
    this.tables = this.tablesCollection.valueChanges();
    return this.tables;
  }
}

Code from the calling component:

tables: IeTables[] = [];

  constructor( private data4eateryservice: Data4eateryService) { }

  ngOnInit() {
    const tablesObservable = this.data4eateryservice.getTables();
    tablesObservable.subscribe((tablesData: IeTables[]) => {
      this.tables = tablesData;
    });

    console.log('Tables', this.tables);
  }

This returns Tables []

All the tutorials I found return observables from constants within the same component. I have been trying to sort this out on and off for weeks so please help me.

Upvotes: 0

Views: 1388

Answers (1)

Harun Yilmaz
Harun Yilmaz

Reputation: 8558

The observable performs an async operation. So you need to assign values after subscribe callback is called, like following:

  tables: IeTables[] = [];

  constructor( private data4eateryservice: Data4eateryService) { }

  ngOnInit() {
    const tablesObservable = this.data4eateryservice.getTables();

    console.log('1 - OnInit Called');
    tablesObservable.subscribe((tablesData: IeTables[]) => {
      this.tables = tablesData;
      console.log('2 - this.tables is set');
    });

    console.log('3 - After subscription');
  }

The above code outputs to console as:

1 - OnInit Called

3 - After subscription

2 - this.tables is set

Therefore, this.tables is not set until the subscription returns a value. So you need to move console.log to inside of subscribe callback like this:

   ngOnInit() {
    const tablesObservable = this.data4eateryservice.getTables();
    tablesObservable.subscribe((tablesData: IeTables[]) => {
      this.tables = tablesData;
      console.log('this.tables: ',this.tables);
    });
  }

I think you need to get more familiar with the fundamentals of Observable from RxJS

Official Angular Docs: https://angular.io/guide/observables

A tutorial: https://appdividend.com/2018/12/08/angular-7-observables-tutorial-with-example/

Another Tutorial: https://codecraft.tv/courses/angular/http/http-with-observables/

Upvotes: 3

Related Questions