Converting Objects to Arrays with Angular Observables

After searching extensively on SO for answers regarding item conversions in Javascript/Angular, I couldn't find a solution that addresses my specific problem. When retrieving data from Firestore as an object with potential duplicates, I need to perform a 1 to many conversion. The object extracted from Firestore is called 'MultipleCard', which includes a property called 'copies' indicating how many 'Cards' should be created.

  postsCol: AngularFirestoreCollection<MultipleCard>;
  posts: Observable<MultipleCard[]>;

  cardsListObservable: Observable<Card[]>; //Undecided
  cardsList: Card[]; //Undecided

  constructor(private messageService: MessageService,
              private db: AngularFirestore) {
    this.messageService.add('Fetching cards');

    this.postsCol = this.db.collection('cards');
    this.posts = this.postsCol.valueChanges();

 //?? Struggling to achieve the desired outcome here. Most operations result in a 1 to 1 conversion or affect the array directly.
}

Component

<mat-list *ngFor="let card of cardsList | async"> //Either cardsList or cardsListObservable
  <mat-list-item>{{card.name}}</mat-list-item> 
 </mat-list>

How can I convert Observable into Observable or Card[]? For example, consider an array containing the following 'MultipleCard's:

 [{ id: 1,
     copies: 3},
    {id: 2, copies:1}]

This array should be transformed into an array of 4 'Card' objects:

[{ id: 1, copyVersion:1},
    { id: 1, copyVersion:2}.
    { id: 1, copyVersion:3},
     { id: 2, copyVersion:1}]

I would appreciate any suggestions!

Edit 1

Attempted the following:

this.posts.subscribe((posts) => {
  posts.forEach( post => {
    console.log(post);
    this.cardsList.push(post);
  });
});

Resulted in:

core.js:1350 ERROR TypeError: Cannot read property 'push' of undefined at eval (deck-list.component.ts:40)

Final Updated Code:

  static fromMultiple(multipleCard: MultipleCard): Card[] {
    const data: Card[] = [];
    for (let i = 0; i < multipleCard.copies; i++) {
      data.push(new Card(multipleCard));
    }
  return data;

}

this.postsCol = this.db.collection('cards');
this.posts = this.postsCol.valueChanges();

this.posts.subscribe((posts) => {
  posts.forEach( post => {
    const temp = Card.fromMultiple(post);
    temp.forEach(tempCard => {
      this.cardsList.push(tempCard);
    });
  });
});

Answer №1

To retrieve data from your collection, you can utilize either valueChanges() or snapshotChanges() methods to return an Observable in response to your request.

Here is an illustration using valueChanges():

this.posts = this.db.collection<MultipleCard[]>('posts').valueChanges();

This line fetches an Observable<MultipleCard[]>, which you can then subscribe to and obtain the MultipleCard[] array as follows:

this.posts.subscribe((posts) => {
   console.log(posts); //This represents the array of posts, not an observable
 });

It's unnecessary to manually subscribe to this in your component because the ASYNC pipe automatically handles it in the markup. You can use a for loop in your markup like this

*ngFor="let post of (posts | async)"
to initiate subscription to your Observable data and terminate it when the component is destroyed. I hope this explanation proves helpful!

I recommend delving deeper into Observable data and the rxjs library being used here for better understanding of the firebase data management process (especially with firestore).

Answer №2

One approach is to either subscribe to your observable stream or convert it into a promise to better understand the data being returned. For example, if a function getData() returns an observable, you can choose to:

getData().subscribe((card: any) => * do something *) 

or

getData().toPromise().then((card: any) => * do something*)  

It's recommended to implement this and log the response (in this case, card). This will provide insights into what is happening behind the scenes.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

"Utilize an Angular button to upload a locally stored JSON file and populate a data

Hey everyone, I'm looking to use a button to load a local file and convert the file data into a jsonObject. The HTML structure: <div class="uuidLableLeft"> <b>Do you want to import your previous file (.json)?</b> <input style ...

What is the best way to run a scheduled task automatically using node-cron?

I have a custom function that saves data to the database using the POST method. When testing it with Postman, I send an empty POST request to trigger the controller. Upon execution, the function triggers two more functions. One of them is responsible for ...

How can I display 4 react components, such as custom buttons, in a manner that ensures the most recently pressed button appears on top?

I've been attempting to solve this problem, but I'm struggling to find a solution. My current approach involves grouping the 4 button components in an array and shifting their positions based on user input. Is there a more efficient way to accomp ...

An effective method for targeting a specific button within a CSS file

I have multiple button tags in my code, but I need to style a specific one using CSS. How can I target this particular button and apply styles only to it while leaving the others unchanged? Do I need to assign the button to a variable and reference that va ...

What is the Typescript compiler utilized by Visual Studio 2015 when compiling on save?

Currently using Visual Studio 2015 Update 3 with TypeScript 2 for VS installed. I have a basic ASP.NET Core MVC web application with a few simple TypeScript files. The project contains a tsconfig.json file in the root folder with "compileOnSave": true. I ...

Middleware for Redux in Typescript

Converting a JavaScript-written React app to Typescript has been quite the challenge for me. The error messages are complex and difficult to decipher, especially when trying to create a simple middleware. I've spent about 5 hours trying to solve an er ...

How to showcase MongoDB data directly on the homepage

Looking for advice on how to display MongoDB database records on the front end of my website using Express. Each record has a category, and I want to organize and display them accordingly. As a beginner, any tips or suggestions would be greatly appreciat ...

Integrating HTTP JSON responses into HTML using Ionic 2, Angular 2, TypeScript, and PHP: A comprehensive guide

Currently in the midst of developing my first Ionic 2 app, however, my understanding of typescript is still limited.. I aim to execute the authenticate() method within my constructor and then to: Retrieve the entire JSON response into the textarea and/o ...

The error code TS2474 (TS) indicates that in 'const' enum declarations, the member initializer must be a constant expression

Error code: export const enum JSDocTagName { Description = "desc", Identifier = "id", Definition = "meaning", } Implementing Angular 6 in conjunction with the .NET framework. ...

The RxDB Angular2-cli error message. "Cannot assign a 'Promise<void>' to a 'Promise<any>' parameter."

I've been grappling with getting RxDB to function properly in a fresh project I initiated using the Angular CLI. Here's my process: ng new <Projectname> After that, I installed RxDB by running: npm install rxdb Following the example p ...

When using the async pipe with Angular's ngFor, an error message indicates that the argument is

Can you explain why this error message is appearing: Argument of type '[string, { startTime: string; endTime: string; }][] | null' is not assignable to parameter of type 'Collection<unknown>'. It occurs when attempting to utilize ...

Incorporating D3.js into Angular 6 for interactive click events

Currently working on building a visual representation of a tree/hierarchy data structure using d3.js v4 within an Angular environment. I've taken inspiration from this particular implementation https://bl.ocks.org/d3noob/43a860bc0024792f8803bba8ca0d5e ...

Why am I unable to apply the keyof operator from one type to another type, even though both types have identical keys defined but different value types?

Consider this code snippet. I am encountering a TypeScript error specifically on the last compat[k] line with the following error message: Type 'keyof T' cannot be used to index type 'Partial<CompatType>' export type KeysOfType ...

An error occurred as the Serverless Function timed out while attempting to load a dynamic route in Next.js version 13

I have a basic Next.js application with the following route structure: /contentA/ - Static - Initial load: 103 kB /contentA/[paramA]/groups - SSG - Initial load: 120 kB /contentB/[paramA]/[paramB]/[paramC] - SSR (client component) - Initial load: 103 kB ...

Using Webpack 4 and React Router, when trying to navigate to a sub path,

I'm currently working on setting up a router for my page, but I've encountered a problem. import * as React from 'react'; import {Route, Router, Switch, Redirect} from 'react-router-dom'; import { createBrowserHistory } from ...

Today is a day for coming together, not for waiting long periods of

When grouping by month and dealing with different days, I encountered an issue similar to the one shown in this image. https://i.stack.imgur.com/HwwC5.png This is a snapshot of my demo code available on stackblitz app.component.html <div *ngFor="let ...

Having trouble locating the angular-devkit while trying to update Angular

I encountered the following error message: An unhandled exception occurred: Cannot find module '@angular/compiler-cli' See "C:\Users\rashe\AppData\Local\Temp\ng-s9ZG05\angular-errors.log" for further details. ...

The revalidation process in react-hook-form doesn't seem to initiate

Stumbled upon a code example here Decided to fork a sandbox version (original had bugs and errors) I am trying to implement custom validation callbacks for each form input element by providing options in the register function, but the validate is only tr ...

Reactive Forms are being loaded dynamically without waiting for the completion of the http call

I've been working on loading dynamic field forms based on input from an HTTP service. The service provides metadata about which fields to load, including the name and type of each field. Therefore, I need to dynamically build the formGroup in ngOnInit ...

The specified property cannot be found within the type 'JSX.IntrinsicElements'. TS2339

Out of the blue, my TypeScript is throwing an error every time I attempt to use header tags in my TSX files. The error message reads: Property 'h1' does not exist on type 'JSX.IntrinsicElements'. TS2339 It seems to accept all other ta ...