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
displayFeed()
is invoked right before the NavController
loads the feed
component on the Main
page.displayFeed()
gets the twiner
item, which is essentially a user profile item, and then stores the user profile in the userProfile
variable.feedCards
Observable is set equal to loadFeed()
, which returns an Observable array.loadFeed()
uses the id
value of the userProfile
global object to load the list of feed references stored in the user profile.feed
variable is set equal to the result list of feed references.loadFeed
returns an Observable object in which the feed
reference list is mapped by the data each feed reference contains.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)
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With