3
votes

In my Website, I want to display a List of Items by their Name. The names are clickable and then the entire doc should be downloaded and you can edit and save the item.

Currently I'm querying collection Data from my FireStore with the way described in the docs: https://github.com/angular/angularfire2/blob/master/docs/firestore/collections.md

  private itemsCollection: AngularFirestoreCollection<Item>;
  items: Observable<Item[]>;
  constructor(private afs: AngularFirestore) {
    this.itemsCollection = afs.collection<Item>('items');
    this.items = this.itemsCollection.valueChanges();
  }

The problem is, I do not want or need realtime Updates for my list. So the Observable approach doesn't really make sense for my app.

The only Way I came up with is that I just use the snapshotChanges Method, and map it to an array, which I then assign to a field. Afterwards the mapping function, sets the items and itemsCollection fields to null, so they don't waste any more bandwidth. But that doesn't seem right to me.

Is there a way to just Query a Collection once, preferrably with Query Parameters, in AngularFire and then display it?

3

3 Answers

5
votes

One way I have handled this is by using the rxjs/add/operator/first. This method fetches the Observable data once then ends the subscription.

just import that library above and make your calls like so:

this.items = this.itemsCollection.valueChanges().first();

then you could subscribe to that and it will only fetch the data once:

this.items.subscribe((items) => { // do something with items array // });

I know there are other methods to handle this using the rxjs do() and take() methods as you may want to look into those. I hope this can be of help!

3
votes

As Nicholas Pesa already answered, using the .first() operator could work, the only thing to note is that it doesn't unsubscribe after emitting a value. If you use the .take(integer) operator though as .take(1), the observable will complete after emitting the first value. That was incorrect. The below note about observables was and is valid though.

By going this way, you are actually making things more difficult for yourself at almost no benefit. The observable approach makes things easier, even if you won't really be utilizing the observable stream approach. Just let the async pipe ( | ) take care of your subscriptions for you, that way you don't have to worry about subscribing or unsubscribing. And if your data isn't changing, then the template will only call upon that collection in firestore the first time.

0
votes

If you want, use the standard Firebase SDK for the Web, which offers promiss-based API (check the docs here) so you can create a getter of type Promise in your service (Or Observable.fromPromise() that will emmit only once):

import * as firebase from 'firebase';

const itemsRef = firebase.firestore().collection('items');

// Into your service:
getItems(): Promise<Item[]> {
  const items: Item[];
  return itemsRef.get()
  .then(colSnap => colSnap.docs().map(snapshot => snapshot.data()));
}