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

Encountering difficulties in creating a new package for angular

I am having trouble generating a new package for Angular. Here are the software version details: npm -v v6.1.0 node -v v8.11.3 ng -v v6.0.8 When attempting to create the project with ng new project_name, I encounter the following error: https:// ...

Is it possible that Angular 6's ngOnChanges directive is not compatible with a lambda expression?

Currently, I am in the process of creating an attribute directive that is designed to alter the background color of the host element based on a provided "quality" @input. While experimenting with my directive, I discovered that using ngOnChanges as a lamb ...

AGM MAP | Placing marker within a custom polygon created on the map

Query Description I am utilizing the AGM_MAP library for an Angular website, which includes a map where users can select an address for their orders. Current Issue The problem I am facing is that when I add a polygon to the map, the marker cannot be p ...

An error has occurred in the tipo-struttura component file in an Angular application connected with a Spring backend and SQL database. The error message indicates that there is a TypeError where the

Working on my project that combines Spring, Angular, and MYSQL, I encountered a challenge of managing three interconnected lists. The third list depends on the second one, which in turn relies on user choices made from the first list. While attempting to l ...

What is the process for defining a recursive array data structure?

Looking to implement a TypeScript method that can navigate through nested arrays of strings when given an instance of a type/class/interface. The method, in concept, should resemble: method<T>(instance: T, arrayAttr: someType) { let tmp = undefin ...

Ways to encourage children to adopt a specific trait

Let's discuss a scenario where I have a React functional component like this: const Test = (props: { children: React.ReactElement<{ slot: "content" }> }) => { return <></> } When a child is passed without a sl ...

Implement ExpressTS on vercel platform

I have recently developed an Express TypeScript project on GitHub and now I am attempting to deploy it to Vercel. The folder structure of the project is as follows, with 'dist' containing app.js and 'src' containing app.ts. dist dto mi ...

What is the correct way to access and assign a value from a different getter or setter? I am facing an issue with the creation of my second array

Two http GET API calls are being made in the constructor. The first call is working fine and has a getter/setter to filter the main array (studentNameData) into a filtered array (filteredName). However, the second call is also trying to do the same thing b ...

One issue that may arise is when attempting to use ngOnDestroy in Angular components while rearranging user transitions

Encountered an issue recently with Angular - when the user navigates from component A to component B, component A remains active unless ngOnDestroy is triggered. However, if the user visits component B before going to component A and then leaves, ngOnDes ...

Extract HTML content using CKEditor

Hey there! I'm in need of some help with getting user-entered data from a textarea. I've already attempted using CKEDITOR.instances.editor1.getData() and CKEDITOR.instances.ckeditor.document.getBody.getHtml(), but unfortunately both only return ...

Angular2's hidden feature isn't functioning properly

There is a common suggestion to use *ngIf better than [hidden] but in my scenario, I want to keep the element in the DOM without it being visible. In my component.html file, I have: <article #articleId id="bodyArticle" [hidden]="isClicked"></art ...

Oops! The type '{}' is lacking the properties listed below

interface Human { firstName: string; lastName: string; } let human1: Human = {}; human1.firstName = "John" human1.lastName = "Doe" Upon declaring human1, an error pops up: Type '{}' is missing the following properties from type Human ...

Implementing Angular functionality with Bootstrap's collapse component

I am currently learning Angular and experimenting with two collapsible div elements. My goal is to have element-1 collapse and element-2 hide when button1 is clicked. Conversely, when button2 is clicked, I want element-2 to collapse and element-1 to hide. ...

Error in Radix UI encountered while attempting to use "react-accordion"

Trying to import the root component of a react accordion and then export it in my project with the name Accordion. However, I keep getting a type error that says Unsafe assignment of an `any` value. I've attempted to fix it by using the as keyword but ...

Error: Trying to access the 'blogpost' property of an undefined variable results in a TypeError while executing the NPM RUN BUILD command in Next.js

Encountering a frustrating issue while trying to run my Next.js application for production build. The problem seems to be related to the "blogpost" parameter in the following codeblock: import React from "react"; import Slab from "../../comp ...

Angular framework does not trigger the button click event

Currently, I am in the process of creating a web app and working on designing the register page. My experience with Angular is still at a beginner level. The following code snippet is from the resiger.component.ts file: /** * To create a new User ...

What strategies can be used to address inconsistencies between the type system and runtime behavior?

I have created a unique TypeScript type called Awaitable<T> with the goal of ensuring that Awaited<Awaitable<T>> is always equal to T. export type Awaitable<T> = | (T extends Record<'then', Function> ? never : T) ...

What is the best approach to validating GraphQL query variables while utilizing Mock Service Worker?

When simulating a graphql query with a mock service worker (MSW), we need to verify that the variables passed to the query contain specific values. This involves more than just type validation using typescript typings. In our setup, we utilize jest along ...

Is it advisable to incorporate 'use server' into every function that retrieves confidential information within server components in Next.js?

By default, server components are enabled in Next.js 13. I'm contemplating whether I should wrap each fetch call in a separate function and include 'use server' to conceal the function's code or if it's acceptable to directly use f ...

An error has occurred: Inconsistency found in metadata versions for angular2-flash-messages

I am currently following the Traversy Media MEAN stack front to back playlist on YouTube. However, I encountered an error after importing the flash-messages and I'm having trouble understanding it. I have tried looking at some GitHub issue pages, but ...