0

So I've read numerous questions on SO about item conversions in Javascript/Angular but am not finding anything that addresses my issues. I'm pulling from Firestore as an object that can have copies. I then need to convert the object using a 1 to many conversion. The object coming from Firestore is a 'MultipleCard'. This 'MultipleCard' has a property called 'copies' which will be used to signify how many 'Cards' should get created.

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

  cardsListObservable: Observable<Card[]>; //Not sure which to use
  cardsList: Card[]; //Not sure which to use

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

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

 //?? Nothing I do here seems to work correctly. Most operations act on the array itself or do a 1 to 1 conversion
}

Component

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

How do I convert Observable into Observable or Card[]? For example I may have an array with the following 'MultipleCard's

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

That should beconverted into an array of 4 'Card' Objects:

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

I appreciate any insight!

Edit 1

Tried the following:

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

But get:

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);
    });
  });
});
11
  • 2
    What is the actual question / issue? Commented Jan 29, 2018 at 21:43
  • @Zze Upddated with a simplified version of the question Commented Jan 29, 2018 at 21:51
  • show your service code? Commented Jan 29, 2018 at 21:53
  • @Haris what service code are you referring to? I'm using the AngularFirestore db to pull the objects right in the class I posted above. Commented Jan 29, 2018 at 22:06
  • You can use map to transform your observable to emit an array instead of whatever firebase returns. i.e. this.posts = this.postsCol.valueChanges().map(x => /*do stuff here*/). Also you should be using the async pipe with an observable, i.e. posts ({{ posts | async }}). Put a breakpoint in your map function - debugging is your friend here. Commented Jan 29, 2018 at 22:11

2 Answers 2

2

You can use valueChanges() or snapshotChanges() on the collection to return the Observable from your request.

Here is an example of valueChanges():

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

so this line returns an Observable<MultipleCard[]> which you can then subscribe to and receive the MultipeCard[] array, like so:

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

You do not need to manually subscribe to this in your component as thats what the ASYNC pipe does for you in the markup. You can set your forLoop in your markup like so *ngFor="let post of (posts | async)" and that will also begin the subscription to your Observable data and also close the subscription when this component is destroyed. I hope this can be of help!

You should do some more research on Observable data and the rxjs library that this is utilizing as it will give you more insight on the data you are handling from firebase (specifically firestore).

Sign up to request clarification or add additional context in comments.

5 Comments

Check out my edit. This is getting me really close but there is still a problem. I think I tried this before but ran into the same error...
Disregard, I never initialized my array cardsList: MultipleCard[] = [];
I see what you are doing there, but just a heads up after you forEach your posts array and then push each item into the cardsList array, you have two arrays there that are exactly the same. The forEach and push are redundant as you are just recreating the same array. You could just do this.cardsList = posts;
Yeah I skipped over the part where I will do the conversation and push multiple objects. The key was the subscribe part combined with the for each loop.
this.db.collection<MultipleCard[]> gives a Observable<MultipleCard[][]> an array of arrays. Should now be this.db.collection<MultipleCard>.
0

You'd either subscribe to your observable stream or promisify it and see what are you getting back. Say a function getData() returns an observable, you can either do

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

or

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

I'd suggest doing this and logging in the response (card here). That way you'll have an idea what's happening.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.