6
votes

I'm trying to assign the data collected from a firestore document to a variable with an Observable type initialised before the constructor.

I've got the data from the collection by passing in a dynamic invoiceId string to the .doc() search, and I can assign the data to a local variable (shown below), but when trying to assign it to this.invoice, I get the following error:

Uncaught (in promise): TypeError: Cannot set property 'invoice' of undefined

-

Component:

import { Component, OnInit, Input } from '@angular/core';

import { ActivatedRoute } from '@angular/router';

import { Observable } from 'rxjs/Observable';

import { AngularFireDatabase } from 'angularfire2/database';

import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from 'angularfire2/firestore';

import { AuthService } from '../../services/auth.service';

import { Invoice } from '../invoiceModel';

@Component({
  selector: 'app-view-invoice',
  templateUrl: './view-invoice.component.html',
  styleUrls: ['./view-invoice.component.scss']
})

export class ViewInvoiceComponent implements OnInit {

  userId: string;

  invoiceId: any;

  invoicesCollection: AngularFirestoreCollection<Invoice>;
  invoices: Observable<Invoice[]>;

  invoice: Observable<Invoice>;

  constructor(private authService: AuthService, private db: AngularFirestore, private route: ActivatedRoute) {
      this.userId = this.authService.user.uid;

      this.route.params.subscribe(params => {
        this.invoiceId = params.id;
      })

      this.invoicesCollection = this.db.collection('/invoices');

      this.invoices = this.invoicesCollection.snapshotChanges().map(changes => {
          return changes.map(a => {
            const data = a.payload.doc.data() as Invoice;
            data.id = a.payload.doc.id;
            return data;
          })
      })
  }

  ngOnInit() {
    this.getInvoice();
  }

  getInvoice() {
    var docref = this.db.collection('/users').doc(this.authService.user.uid).collection('/invoices').doc(this.invoiceId);
    docref.ref.get()
        .then(function(doc) {
            if (doc.exists) {
                var invoice = doc.data(); <------WORKS
                // this.invoice = doc.data(); <------DOESN'T WORK
                console.log('Invoice data: ', doc.data());
            } else {
                console.error('No matching invoice found');
            }
    })
  }

}
3
Try creating a shallow reference of this. as in getInvoice() { const _that=this; and then within doc.exists try _that.invoice = doc.data() - Guruprasad J Rao
Just tried that but it means this.invoice still doesn't get the data, I need the data to be made available anywhere in the component, not just in this function - nick.cook
Yes.. Probably. because scope of this would not be actually Component since it is within a promise. That's my guess.. So you are able to set it with _that? - Guruprasad J Rao
Yes, I can set it with that, but it needs to be accessible data anywhere in the scope of the component - nick.cook
Yes.. That will be possible. But only in certain places, you won't be having access to the scope with this. But the changes you make with _that actually affects the original variable.. :) - Guruprasad J Rao

3 Answers

1
votes

I was fighting the same thing. It was driving me crazy!! I'm a newbie, but I appear to have solved your issue by changing one line of code:

.then(function(doc) {   //changed from
.then((doc) => {        //changed to (removed the function)

I don't even understand the ramifications of doing so, but the scope is now working to assign the value of the variable.

1
votes

If you are using AngularFire you can do:

invoiceCol: AngularFirestoreCollection<Invoice>;
invoiceObservableArray: Observable<Invoice[]>;
invoiceArray: Invoice[];

constructor(private db: AngularFirestore) { } //--injection

getAllInvoice() { //getting data of DB
    this.invoiceCol= this.db.collection('yourInvoiceDbPath');
    return this.invoiceCol.valueChanges();
}

this.invoiceObservableArray.getAllInvoice();//calling method above

this.invoiceObservableArray.subscribe(invoice=> { //converting oberv in array
      this.invoiceArray = invoice;
    });

console.log(this.invoiceArray); //showing in console
0
votes
getInvoice() {

let _this = this; <---***

    var docref = this.db.collection('/users').doc(this.authService.user.uid)
                     .collection('/invoices').doc(this.invoiceId);
    docref.ref.get()
        .then(function(doc) {
            if (doc.exists) {
                var invoice = doc.data(); <------WORKS
                // this.invoice = doc.data(); <------WORKS
                console.log('Invoice data: ', doc.data());
            } else {
                console.error('No matching invoice found');
            }
    })
  }