0

I need two functions to return all data as well as specific filtered data, but my constructs are wrong. Below is what "think" I want, but am returning Subscriptions instead of arrays:

   allItems() {

      var collectionAll: AngularFirestoreCollection<Item> =
         this._afs.collection<Item>('items');

      var itemArray$: Observable<Item[]> =
         collectionAll.valueChanges();

      // Returns Subscription but I need Items[]
      return itemArray$.subscribe(items => {
         return items;
      })
   }

   specificItems(name: string) {

      var collectionSpecific: AngularFirestoreCollection<Item> =
         this._afs.collection<Item>('items', ref =>
            ref.where('name', '==', name));

      var itemArray$: Observable<Item[]> =
         collectionSpecific.valueChanges();

      // Returns Subscription but I need Items[]
      return itemArray$.subscribe(items => {
         return items;
      })
   }

Also I would think that it would need to be an async function, but the subscribe function doesn't return a promise.

And I'm not even sure at what point I would actually be charged a read count from Firestore...?

Dharman
  • 30,962
  • 25
  • 85
  • 135
Love to Code
  • 425
  • 1
  • 5
  • 16
  • Possible duplicate of [angular 2 how to return data from subscribe](https://stackoverflow.com/questions/39295854/angular-2-how-to-return-data-from-subscribe) – Harun Yilmaz Sep 23 '19 at 15:03
  • Possible duplicate of [How do I return the response from an Observable/http/async call in angular?](https://stackoverflow.com/questions/43055706/how-do-i-return-the-response-from-an-observable-http-async-call-in-angular) – Heretic Monkey Sep 23 '19 at 15:15

3 Answers3

1

If you want a promise, you need to convert the Observable to a Promise using toPromise:

specificItems(name: string): Promise<Item[]> {
  var collectionSpecific: AngularFirestoreCollection<Item> =
     this._afs.collection<Item>('items', ref =>
        ref.where('name', '==', name));

  var itemArray$: Observable<Item[]> =
     collectionSpecific.valueChanges();

  return itemArray$.toPromise();
}
Andrei Tătar
  • 7,872
  • 19
  • 37
  • Andrei, that does answer my question as asked so I accepted your answer. I think though that I may have the wrong approach which prompted the question in the first place (response to Maryannah). Thank you though. – Love to Code Sep 23 '19 at 19:31
0

Observables are very powerful, you should keep them as is.

allItems = this._afs.collection<Item>('items').valueChanges();

In your template, you can simply use the async pipe to read your data :

<div *ngFor="let items of allItems | async">...</div>

This is the most powerful way of using Angular for several reasons, so try learning it as soon as possible, because basically Angular = RxJS (not true of course, but it shows you how much you need RxJS in Angular)

  • Observables are still a mind-shift for me. ;) Can they be used to add to? In my example, I intended to create an array of items and then add to it during the user's session (getting all the items named 'ABC', then adding 'DEF', etc.). Is that possible using Observables? As Andrei indicated, changing to a promise would get the array, but maybe my approach is incorrect? – Love to Code Sep 23 '19 at 19:17
  • Observables are enhanced promises, what promises can do, they can do it better. Anybody telling you otherwise doesn't understand observables. And his solution just returns a promise, it doesn't return an observable. Using async keywords do. But given that JS has a single thread, that means you block it for the duration of your call. I wouldn't say it's bad practice, but it's definitely not a good one. –  Sep 23 '19 at 20:10
  • @LovetoCode Oh and for the read count of firebase, one request = +1. You have like 30k operations per month, so you should be fine ! –  Sep 23 '19 at 20:12
0

Declare the below model in different location so that you can reuse the same model.

  export class EmployeeRoster {
        RosterDate: Date;
        EmployeeId: number;
        RosterDayName: string;
        ProjectId: number;
        ShiftId: number;
        ShiftTime: string;
        ShiftColor: string;
        IsOnLeave: boolean;
    }

Declare the below method in your service layer.

      GetSavedEmployeeData(empIds: EmployeeIdlistToRoster[], sDate: string, eDate: string): Observable<EmployeeRoster[]> { 
        let empIdsValue = '';
        if (empIds !== null && empIds.length > 0) {
          empIds.forEach(function (em) {
            empIdsValue += em.EmpId + ',';
          });
        }

        //How to pass value as a parameter
        const paramsdsf = new HttpParams()
          .set('empIds', empIdsValue)
          .append('sDate', sDate)
          .append('eDate', eDate);
        return this.http.get<EmployeeRoster[]>(apiUrl, { params: paramsdsf });
      }

This is just an example you can update this method and model as per your requirement.

vijay sahu
  • 765
  • 1
  • 7
  • 29