最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Ionic 3 - Update Observable with Asynchronous Data - Stack Overflow

programmeradmin1浏览0评论

For a social media app, I have a collection of feed objects referenced by their IDs using AngularFire 2. Once each of these IDs has its relevant data pulled from the database that stores the actual feed objects, I wish to update the feedCards Observable object with this information so I can asynchronously display a collection of feed objects in my HTML. It's a pretty confusing chain of events, so let me summarize it for you.

Step-by-step Approach

  1. displayFeed() is invoked right before the NavController loads the feed ponent on the Main page.
  2. displayFeed() gets the twiner item, which is essentially a user profile item, and then stores the user profile in the userProfile variable.
  3. Once the user profile is loaded, the global feedCards Observable is set equal to loadFeed(), which returns an Observable array.
  4. loadFeed() uses the id value of the userProfile global object to load the list of feed references stored in the user profile.
  5. This snapshot is then subscribed to and the local feed variable is set equal to the result list of feed references.
  6. loadFeed returns an Observable object in which the feed reference list is mapped by the data each feed reference contains.
  7. pullFeedData(number) takes in a reference to a feed object and returns an observable with the associated feed data.

What Works

  • alert(JSON.stringify(feedData)); alerts the correct feed object

  • Basically everything else.

What Doesn't Work

  • feed.map(... does not update the feed array because pullFeedData(number) pulls and returns the feedData asynchronously. Thus, alert(JSON.stringify(data)); in displayFeed() alerts [null].

Code

feed.ts

   userProfile:any;
   feed: FirebaseListObservable<any>;
   feedData: FirebaseObjectObservable<any>;

   feedCards: Observable<any[]>;

   constructor(public db: AngularFireDatabase, public nativeStorage: NativeStorage) {}

   displayFeed():void {
        this.nativeStorage.getItem('twiner').then((res) => {
              this.userProfile = res;
              this.feedCards = this.loadFeed();
              this.feedCards.subscribe((data)=>{
                    alert(JSON.stringify(data));
              })
        });
  }

  loadFeed():Observable<any[]> {
        var feed;
        this.feed = this.db.list('/twiners/' + this.userProfile.id + '/feed', { preserveSnapshot: true });
        this.feed.subscribe((snapshots)=>{feed = snapshots});
        return Observable.of(feed.map((snapshot) => {
              this.pullFeedData(snapshot.val()).subscribe((feedData)=>{
                    alert(JSON.stringify(feedData));
                    return feedData;
              });
        })).delay(1000);
  }

  pullFeedData(twine:number):any {
        return this.db.object('/twines/' + twine, { preserveSnapshot: true });
  }

feed.html

<ion-content fullscreen scroll="true" overflow-scroll="true">
      <ion-card *ngIf="feedCards | async">feedCards exist</ion-card>
      <twine-feed-card *ngFor="let feedCard of feedCards | async"
            [data]="feedCard"
      ></twine-feed-card>
</ion-content>

Summary

feed.map does not update feed with feed objects because the new data is being pulled asynchronously. I need a fix for this.

Thank you!

For a social media app, I have a collection of feed objects referenced by their IDs using AngularFire 2. Once each of these IDs has its relevant data pulled from the database that stores the actual feed objects, I wish to update the feedCards Observable object with this information so I can asynchronously display a collection of feed objects in my HTML. It's a pretty confusing chain of events, so let me summarize it for you.

Step-by-step Approach

  1. displayFeed() is invoked right before the NavController loads the feed ponent on the Main page.
  2. displayFeed() gets the twiner item, which is essentially a user profile item, and then stores the user profile in the userProfile variable.
  3. Once the user profile is loaded, the global feedCards Observable is set equal to loadFeed(), which returns an Observable array.
  4. loadFeed() uses the id value of the userProfile global object to load the list of feed references stored in the user profile.
  5. This snapshot is then subscribed to and the local feed variable is set equal to the result list of feed references.
  6. loadFeed returns an Observable object in which the feed reference list is mapped by the data each feed reference contains.
  7. pullFeedData(number) takes in a reference to a feed object and returns an observable with the associated feed data.

What Works

  • alert(JSON.stringify(feedData)); alerts the correct feed object

  • Basically everything else.

What Doesn't Work

  • feed.map(... does not update the feed array because pullFeedData(number) pulls and returns the feedData asynchronously. Thus, alert(JSON.stringify(data)); in displayFeed() alerts [null].

Code

feed.ts

   userProfile:any;
   feed: FirebaseListObservable<any>;
   feedData: FirebaseObjectObservable<any>;

   feedCards: Observable<any[]>;

   constructor(public db: AngularFireDatabase, public nativeStorage: NativeStorage) {}

   displayFeed():void {
        this.nativeStorage.getItem('twiner').then((res) => {
              this.userProfile = res;
              this.feedCards = this.loadFeed();
              this.feedCards.subscribe((data)=>{
                    alert(JSON.stringify(data));
              })
        });
  }

  loadFeed():Observable<any[]> {
        var feed;
        this.feed = this.db.list('/twiners/' + this.userProfile.id + '/feed', { preserveSnapshot: true });
        this.feed.subscribe((snapshots)=>{feed = snapshots});
        return Observable.of(feed.map((snapshot) => {
              this.pullFeedData(snapshot.val()).subscribe((feedData)=>{
                    alert(JSON.stringify(feedData));
                    return feedData;
              });
        })).delay(1000);
  }

  pullFeedData(twine:number):any {
        return this.db.object('/twines/' + twine, { preserveSnapshot: true });
  }

feed.html

<ion-content fullscreen scroll="true" overflow-scroll="true">
      <ion-card *ngIf="feedCards | async">feedCards exist</ion-card>
      <twine-feed-card *ngFor="let feedCard of feedCards | async"
            [data]="feedCard"
      ></twine-feed-card>
</ion-content>

Summary

feed.map does not update feed with feed objects because the new data is being pulled asynchronously. I need a fix for this.

Thank you!

Share Improve this question edited May 28, 2017 at 17:46 Anthony Krivonos asked May 28, 2017 at 16:45 Anthony KrivonosAnthony Krivonos 4,7264 gold badges18 silver badges32 bronze badges 5
  • did you try running it inside zones..? (I used to use listobservables, now I use event emitters to achieve this real-time functionality) – Raja Yogan Commented May 28, 2017 at 19:10
  • @RajaYogan Do you mind reiterating how to use this functionality in zones? In short, I don't know what that is. – Anthony Krivonos Commented May 28, 2017 at 23:39
  • No probs.. do you get the data here in an alert..? this.feedCards.subscribe((data)=>{ alert(JSON.stringify(data)); }) – Raja Yogan Commented May 29, 2017 at 8:23
  • @RajaYogan Nope, I don't. I put that in my original question. – Anthony Krivonos Commented May 29, 2017 at 14:07
  • I think you need to look at promises. They basically set up a callback function that gets called after the asynchronous behavior is plete. – BobRodes Commented Jun 1, 2017 at 5:14
Add a ment  | 

1 Answer 1

Reset to default 6 +100

A subscribed observable does not return a value. It returns a Subscription object which you can use to unsubscribe later.

You can use switchMap to switch from first observable to the next during the call and return the values. Also you can use forkJoin which will call an array of observables and wait till the array of values is returned in subscription. First declare feed class variable as an Observable.

feed: Observable<any>;

Then in your loadFeed():Observable<any[]>

return this.feed.switchMap((snapshots) => {
             let observableArray = [];
             snapshots.forEach(snapshot =>{
                 observableArray.push(this.pullFeedData(snapshot.val()));
             });
             return Observable.forkJoin(observableArray)
        })
发布评论

评论列表(0)

  1. 暂无评论