Ionic 3 - 使用异步数据更新 Observable
对于社交媒体应用程序,我有一组使用 AngularFire 2
由其 ID 引用的提要对象.一旦这些 ID 中的每一个都从存储实际提要对象的数据库中提取了相关数据,我希望使用此信息更新 feedCards
可观察对象,以便我可以异步显示提要对象的集合.HTML.这是一个相当混乱的事件链,所以让我为你总结一下.
循序渐进的方法
displayFeed()
在NavController
加载Main
页面上的feed
组件之前调用.displayFeed()
获取twiner
项,它本质上是一个用户配置文件项,然后将用户配置文件存储在userProfile
变量中.- 加载用户配置文件后,全局
feedCards
Observable 将设置为等于loadFeed()
,返回一个 Observable 数组. loadFeed()
使用userProfile
全局对象的id
值来加载存储在用户配置文件中的提要参考列表.- 然后订阅此快照并将本地
feed
变量设置为等于提要引用的结果列表. loadFeed
返回一个 Observable 对象,其中feed
引用列表由每个提要引用包含的数据映射.pullFeedData(number)
接受对 feed 对象的引用并返回一个带有相关 feed 数据的 observable.
<块引用>
什么有效
alert(JSON.stringify(feedData));
提醒正确的feed
对象基本上其他的.
什么不起作用
feed.map(...
不会更新 feed 数组,因为pullFeedData(number)
会异步拉取并返回feedData
.因此,alert(JSON.stringify(data));
indisplayFeed()
警报[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
displayFeed()
is invoked right before theNavController
loads thefeed
component on theMain
page.displayFeed()
gets thetwiner
item, which is essentially a user profile item, and then stores the user profile in theuserProfile
variable.- Once the user profile is loaded, the global
feedCards
Observable is set equal toloadFeed()
, which returns an Observable array. loadFeed()
uses theid
value of theuserProfile
global object to load the list of feed references stored in the user profile.- This snapshot is then subscribed to and the local
feed
variable is set equal to the result list of feed references. loadFeed
returns an Observable object in which thefeed
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 correctfeed
objectBasically everything else.
What Doesn't Work
feed.map(...
does not update the feed array becausepullFeedData(number)
pulls and returns thefeedData
asynchronously. Thus,alert(JSON.stringify(data));
indisplayFeed()
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)
})
相关文章