1
votes

I have a document containing mapping/objects in my firestore database, and I would like to convert the observable I get from this into an array in my application

Data in firestore: Firestore- GameInfo/Categories

would give me:

this.categories = [
{ "Action" : {
"title" : "Action",
"description" : "combines elements of..."}
},
{"Platformer" : {
"title" : "Platformer",
"description" : "..."} 
},
{ so on so fourth... 
}
]

Ive tried various approaches, each giving me unreliable or no results. These are the approaches I have tried:

  1. Call valueChanges() on the firestore observable, then unwrap with async pipe in my view.
  2. Subscribe to the observable in NgOnInit of my component.

Returning the raw observable and unwrapping it gives the most reliable results. I can view it in my markup like so

<p>{{ categories | async | json }}</p>

But I'm unable to loop over it, which my view requires. Hence needing the data as an array.

Alternately, subscribing to the observable in my component gives me the following error in the dev tools console:

Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays

This error leads me to think I am doing something wrong. I cannot treat mapping an observable to an array the way i would with a regular variable like this:

gameInfoService.categories$.subscribe(resp => this.categories = resp);

I viewed a similar post to this, where the solution was to use the .pipe(map()) operator on the valueChanges method, then assign the callback value's members to an object freshly created in that block, then return that object. Unfortunately, that solution does not work for me because it deals with collections whereas I am trying to do the same thing with a document.

1
Are you sure the returned data from your observable is an array? You could console print the observables data to check.MoxxiManagarm

1 Answers

0
votes

@MoxxiManagarm suggestion was helpful. So I added this to my service:

get creators$() : Observable <Game_Descriptor []> {
    return this.gameInfoCollection
    .doc<Game_Descriptor []>('/creators').valueChanges();
}

This is the solution for my component:

ngOnInit(): void {
    this.gameInfoService.creators$.subscribe(arr => {
        this.creators = Object.keys(arr).map(creatorTitle => {
            return arr[creatorTitle]
        });            
    });
}

I suppose I was failing to see that the return type of the observable is an object, regardless of what I told the return value of the method shown above to be (I guess, because its JSON- correct me if I am wrong!). So I had to manually coerce that into an array within the subscription

Finally, rendered it in my view using:

<ul>
    <li *ngFor="let g of creators">
        <a [routerLink]="g.title">{{ g.title }}</a>
    </li>
</ul>