title: Angular / Firestore - Get single document and access in view template
body: <p>I have been trying for about a week to get a single document from a firestore collection and access it via selectors in the view template like <code>{{invoice.id}}</code>.</p>
  
  <p>I've tried four different methods, as shown below, to try and get the data from the document in a way that enables it to be used as an ordinary object in the template, but the closest I've been able to get is outputting the object with the json pipe in the selector, like this <code>{{ invoice | json }}</code>.</p>
  
  <p>This outputs the correct data in json format, but when trying to use a field selector on the invoice object, it returns undefined, and logging out <code>this.invoice</code> to the console outputs it as the AngularFirestoreDocument.</p>
  
  <p><strong>view-invoice.component.html:</strong></p>
  
  <pre><code>&lt;!-- (These return 'undefined'
  
    &lt;p&gt;{{ invoice.id }} &lt;/p&gt;
  
    &lt;p&gt;{{ (invoice | async)?.id }}&lt;/p&gt;
  
  --&gt;
  
  &lt;!-- This outputs correctly as json --&gt;
  &lt;p&gt;{{ invoice | json }}
  </code></pre>
  
  <p>-</p>
  
  <p><strong>view-invoice.component.ts:</strong></p>
  
  <pre><code>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';import 'rxjs/add/operator/mergeMap';
  
  @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&lt;Invoice&gt;;
    invoices: Observable&lt;Invoice[]&gt;;
  
    invoiceDoc: AngularFirestoreDocument&lt;Invoice&gt;;
    invoice: Observable&lt;Invoice&gt;;
  
    constructor(private authService: AuthService, private db: AngularFirestore, private route: ActivatedRoute) {
      this.userId = this.authService.user.uid;
  
      this.route.params.subscribe(params =&gt; {
          this.invoiceId = params.id;
      })
  
      this.invoicesCollection = this.db.collection('/invoices');
  
      this.invoices = this.invoicesCollection.snapshotChanges().map(changes =&gt; {
          return changes.map(a =&gt; {
              const data = a.payload.doc.data() as Invoice;
              data.id = a.payload.doc.id;
              return data;
          })
      })
    }
  
    ngOnInit() {
      this.getInvoice();
      console.log('this.invoice: ');
      console.log(this.invoice);
    }
  
    getInvoice() {
  
      /* #1 - CURRENT ATTEMPT - THIS.INVOICE OUTPUTS AS 'UNDEFINED' IN CONSOLE, BUT CAN OUTPUT AS JSON IN VIEW */
      const that = this;
      var invoicedoc = this.db.collection('/users').doc(this.userId).collection('/invoices').doc&lt;Observable&lt;Invoice&gt;&gt;(this.invoiceId);
      invoicedoc.valueChanges()
          .subscribe(a =&gt; {
              that.invoice = a as Observable&lt;Invoice&gt;;
          })
  
      /* #2 - RETURNS SAME AS #1
      this.invoiceDoc = this.db.doc&lt;Invoice&gt;('/users' + this.userId + '/invoices' + this.invoiceId);
      this.invoice = this.invoiceDoc.valueChanges();
      */
  
      /* #3 -  RETURNS SAME AS #1
      this.invoice = this.db.collection('/users').doc(this.userId).collection('/invoices', ref =&gt; ref.where('invoiceId', '==', this.invoiceId).limit(1)).valueChanges().flatMap(result =&gt; result);
      */
  
      /* #4 -  LOGGING THIS.INVOICE TO CONSOLE RETURNS 'UNDEFINED'
      const _that = this;
      var docref = this.db.collection('/users').doc(this.authService.user.uid).collection('/invoices').doc&lt;Invoice&gt;(this.invoiceId);
      docref.ref.get()
          .then(function(doc) {
              if (doc.exists) {
                  var invoice = doc.data();
                  _that.invoice = doc.data() as Invoice;
                  console.log('Invoice data: ', doc.data());
              } else {
                  console.error('No matching invoice found');
              }
      })
      */
  
    }
  
  }
  </code></pre>