Ionic 3 - 使用异步数据更新 Observable

对于社交媒体应用程序,我有一组使用 AngularFire 2 由其 ID 引用的提要对象.一旦这些 ID 中的每一个都从存储实际提要对象的数据库中提取了相关数据,我希望使用此信息更新 feedCards 可观察对象,以便我可以异步显示提要对象的集合.HTML.这是一个相当混乱的事件链,所以让我为你总结一下.

<块引用>

循序渐进的方法

  1. displayFeed()NavController 加载 Main 页面上的 feed 组件之前调用.
  2. displayFeed() 获取 twiner 项,它本质上是一个用户配置文件项,然后将用户配置文件存储在 userProfile 变量中.
  3. 加载用户配置文件后,全局 feedCards Observable 将设置为等于 loadFeed(),返回一个 Observable 数组.
  4. loadFeed() 使用 userProfile 全局对象的 id 值来加载存储在用户配置文件中的提要参考列表.
  5. 然后订阅此快照并将本地 feed 变量设置为等于提要引用的结果列表.
  6. loadFeed 返回一个 Observable 对象,其中 feed 引用列表由每个提要引用包含的数据映射.
  7. pullFeedData(number) 接受对 feed 对象的引用并返回一个带有相关 feed 数据的 observable.

<块引用>

什么有效

  • alert(JSON.stringify(feedData)); 提醒正确的 feed 对象

  • 基本上其他的.

<块引用>

什么不起作用

  • feed.map(... 不会更新 feed 数组,因为 pullFeedData(number) 会异步拉取并返回 feedData.因此, alert(JSON.stringify(data)); in displayFeed() 警报 [null].
<块引用>

代码

feed.ts

 userProfile:any;提要:FirebaseListObservable<any>;feedData: FirebaseObjectObservable<any>;feedCards:可观察的<any[]>;构造函数(公共数据库:AngularFireDatabase,公共 nativeStorage:NativeStorage){}displayFeed():无效{this.nativeStorage.getItem('twiner').then((res) => {this.userProfile = res;this.feedCards = this.loadFeed();this.feedCards.subscribe((数据)=>{警报(JSON.stringify(数据));})});}loadFeed():Observable<any[]>{变种饲料;this.feed = this.db.list('/twiners/' + this.userProfile.id + '/feed', { preserveSnapshot: true });this.feed.subscribe((snapshots)=>{feed = snapshots});返回 Observable.of(feed.map((snapshot) => {this.pullFeedData(snapshot.val()).subscribe((feedData)=>{警报(JSON.stringify(feedData));返回饲料数据;});})).延迟(1000);}pullFeedData(麻线:数字):任何{return this.db.object('/twines/' + twine, { preserveSnapshot: true });}

feed.html

<块引用>

总结

feed.map 不会用 feed 对象更新 feed,因为新数据是异步提取的.我需要解决这个问题.

谢谢!

解决方案

订阅的 observable 没有返回值.它返回一个 Subscription 对象,您可以稍后使用它来取消订阅.

您可以在调用过程中使用 switchMap 从第一个 observable 切换到下一个 observable 并返回值.你也可以使用 forkJoin 来调用一个 observables 数组并等到值数组在订阅中返回.首先将 feed 类变量声明为 Observable.

feed: Observable<any>;

然后在你的 loadFeed():Observable<any[]>

return this.feed.switchMap((snapshots) => {让 observableArray = [];快照.forEach(快照 =>{observableArray.push(this.pullFeedData(snapshot.val()));});返回 Observable.forkJoin(observableArray)})

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 component 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!

解决方案

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

相关文章