0
votes

I'm using AngularFire to retrieve an array of docs from the firestore database. In the developer console it shows the data being fetched, but the table isn't populating on the site. Here's my service class:

import { Injectable } from '@angular/core';
import {Observable, of} from 'rxjs';
import { AngularFirestore, DocumentData } from '@angular/fire/firestore';
import { AngularFireAuth } from '@angular/fire/auth';


@Injectable({
  providedIn: 'root'
})
export class DatabaseHandlerService {
  constructor(private afStore: AngularFirestore, private afAuth: AngularFireAuth) {

  }

  // Get my complaints asynchronously
  getMyComplaints(): Observable<Item[]>{

    const usID = this.afAuth.auth.currentUser.uid;
    const newstuff = [];

    this.afStore.collection('user').ref.where('userID','==',usID).get().then(function(snapshot) {
      snapshot.docs[0].ref.collection('mycomplaints').
      get().then(function(snapshot){
        //console.log(snapshot.docs[0].data());
        snapshot.forEach(function(doc){
          newstuff.push(doc.data());
        });  
      });
    });

    return of(newstuff as Item[]);
  }

}

I'm subscribing to the Observable in my component class like the following shows:

 ngOnInit() {
    this.getComplaints();
  }

  getComplaints(): void {
    this.handler.getMyComplaints().pipe(debounceTime(20), delay(20)).
    subscribe(data => { 
      this.dataSource = new MatTableDataSource(data);
      console.log(data);
    },error=>{
      console.log(error);
    },()=>{
      console.log('Data fetched');
    });
  }

I tried using the forkJoin function instead of the of function to return the Observable but that didn't fetch any data at all; the forkJoin was suggested in the following link.

Edited: Here is the template file for the MatTable:

<div class="container mt-5 pb-5">
    <div class="text-center mb-5 mt-5">
        <h1>My Complaints</h1>
    </div>
    <mat-form-field>
        <input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
        <mat-icon matSuffix>search</mat-icon>
    </mat-form-field>

    <mat-table [dataSource]="dataSource" class="mat-elevation-z8">
        <ng-container matColumnDef="badgeNumber">
            <mat-header-cell *matHeaderCellDef> Badge #
            </mat-header-cell>
            <mat-cell *matCellDef="let element"> {{element.badgeNumber}} </mat-cell>
        </ng-container>
        <ng-container matColumnDef="lastName">
            <mat-header-cell *matHeaderCellDef> Last Name
            </mat-header-cell>
            <mat-cell *matCellDef="let element"> {{element.lastName}} </mat-cell>
        </ng-container>
        <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
        <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
    </mat-table>


</div>
2
I'm not familiar with Angularfire, but for sure I can see some problems with your code. You're returning the data before it gets populated (you should have waited for it). You're using function instead of arrow-functions and it can be problematic if you need this. Take a look at the docs for sub-collection and see if it helps.developer033

2 Answers

0
votes

1

since you are updating the datasource in a subscribe, you should use ChangeDetectorRef to update the view.

inject the ChangeDetectorRef into the construnctor.

constructor(private cd: ChangeDetectorRef)

and inside the .subscribe() add :

this.cd.markForCheck()

2

in your .html file

<table mat-table [dataSource]="dataSource | async">

and in your .ts file

 getComplaints():Observable<Item[]{
  this.dataSource = this.handler.getMyComplaints().pipe(debounceTime(20), delay(20));
  }
0
votes

I got it to work by removing debounceTime operator and increasing the delay operator interval from 20ms to 1000ms. From my observation, the client-side MatTable component needed more time to render before receiving asynchronous data. The component class now looks like this:

 ngOnInit() {
    this.getComplaints();
  }

  getComplaints(): void {
    this.handler.getMyComplaints().pipe(delay(1000)).
    subscribe(data => { 
      this.dataSource = new MatTableDataSource(data);
      console.log(data);
    },error=>{
      console.log(error);
    },()=>{
      console.log('Data fetched');
    });
  }

Thank you for helping me @alin0509 and @developer033