7

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');
            }
    })
  }

}
14
  • Try creating a shallow reference of this. as in getInvoice() { const _that=this; and then within doc.exists try _that.invoice = doc.data() Commented Mar 2, 2018 at 10:39
  • 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 Commented Mar 2, 2018 at 10:53
  • 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? Commented Mar 2, 2018 at 10:54
  • Yes, I can set it with that, but it needs to be accessible data anywhere in the scope of the component Commented Mar 2, 2018 at 10:55
  • 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.. :) Commented Mar 2, 2018 at 10:57

3 Answers 3

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

It's because arrow functions do not have the same scope as functions. The latter basically define a new scope for this.
1

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

Comments

1
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');
            }
    })
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.