Angular Observable Array Object Conversion

2019-08-21 09:10发布

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);
    });
  });
});

2条回答
手持菜刀,她持情操
2楼-- · 2019-08-21 09:43

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).

查看更多
甜甜的少女心
3楼-- · 2019-08-21 10:02

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.

查看更多
登录 后发表回答