جافاسكريبت - أيونيك 3 - تحديث Observable بالبيانات غير المتزامنة


لتطبيق وسائط اجتماعية، لدي مجموعة من كائنات الخلاصات المشار إليها بواسطة معرفاتها باستخدام AngularFire 2. بمجرد سحب البيانات ذات الصلة بكل من هذه المعرفات من قاعدة البيانات التي تخزن الكائنات الفعلية للخلاصات، أرغب في تحديث كائن feedCards Observable بهذه المعلومات حتى أتمكن من عرض مجموعة من كائنات الخلاصات بشكل غير متزامن في HTML الخاص بي. إنها سلسلة أحداث مربكة إلى حد ما، لذا دعني ألخصها لك.

نهج خطوة بخطوة

  1. يتم استدعاء displayFeed() مباشرة قبل أن يقوم NavController بتحميل مكون feed على صفحة Main.
  2. displayFeed() يحصل على عنصر twiner، الذي هو في الأساس عنصر ملف تعريف المستخدم، ثم يخزن ملف تعريف المستخدم في المتغير userProfile.
  3. بمجرد تحميل ملف المستخدم، يتم تعيين Observable العام feedCards مساويًا لـ loadFeed()، والذي يعيد مصفوفة Observable.
  4. loadFeed() يستخدم قيمة id للكائن العالمي userProfile لتحميل قائمة المراجع الخاصة بالتغذية المخزنة في ملف تعريف المستخدم.
  5. يتم بعد ذلك الاشتراك في هذه اللقطة ويتم تعيين المتغير المحلي feed مساويًا لقائمة النتائج لمراجع الخلاصة.
  6. loadFeed تُرجع كائن Observable حيث يتم تحويل قائمة المراجع feed بالبيانات التي يحتوي عليها كل مرجع من مراجع الـ feed.
  7. تأخذ الدالة pullFeedData(number) مرجعًا إلى كائن التغذية وترجع كائنًا قابلاً للمراقبة مع بيانات التغذية المرتبطة.

ما يصلح

  • alert(JSON.stringify(feedData)); يعرض تنبيهًا بالكائن feed الصحيح

  • بشكل أساسي كل شيء آخر.

ما لا يعمل

  • لا يقوم feed.map(... بتحديث مصفوفة التغذية لأن pullFeedData(number) يسحب ويعيد feedData بشكل غير متزامن. وبالتالي، فإن alert(JSON.stringify(data)); في displayFeed() يعرض [null].

كود

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>

ملخص

لا يقوم feed.map بتحديث feed مع كائنات التغذية لأن البيانات الجديدة يتم سحبها بشكل غير متزامن. أحتاج إلى حل لهذا.

شكراً لك!

الإجابة رقم 1

المراقب المشترك لا يُرجع قيمة. إنه يُرجع كائن Subscription يمكنك استخدامه لإلغاء الاشتراك لاحقًا.

يمكنك استخدام switchMap للتبديل من المراقب الأول إلى التالي أثناء الاستدعاء وإرجاع القيم. يمكنك أيضًا استخدام forkJoin الذي سيستدعي مجموعة من المراقبين وينتظر حتى يتم إرجاع مجموعة القيم في الاشتراك. أولاً، قم بالإعلان عن متغير الفصل feed كـ Observable.

feed: Observable<any>;

ثم في loadFeed():Observable<any[]> الخاص بك

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