I'm trying (with partial success :( ) to retrieve full objects as observables from a collection of indexes of my firebase RTDB using angularfire2 basic methods such as list() and object() in an Ionic app. When retrieving the list of keys for the courses a user has enrolled on I make a new query and get the full data as an observable using the object() method. I get several null in the view when loading the page for the first time but the observables are still alive, so if I make a small change in those objects in the console, the whole object is retrieved and shown in the view without any problem. Am I missing something?
Firebase RTDB root-level nodes
This is my page ts code
import { Component, ViewChild } from '@angular/core';
import { NavController, NavParams, List } from 'ionic-angular';
import { ProfileServiceProvider } from '../../providers/profile-service/profile-service';
import { MomentsFeedPage } from '../moments-feed/moments-feed';
import { CourseServiceProvider } from '../../providers/course-service/course-service';
import { AngularFireDatabase } from 'angularfire2/database';
import { Observable } from 'rxjs/Observable';
/**
* Generated class for the MomentsPage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
@Component({
selector: 'page-moments',
templateUrl: 'moments.html',
})
export class MomentsPage{
@ViewChild('enrolledList', { read: List }) enrolledList: List;
public enrolledLis: Observable <{}>;
constructor(
public navCtrl: NavController,
public navParams: NavParams,
public courseService: CourseServiceProvider,
public userProfile: ProfileServiceProvider,
public afDB: AngularFireDatabase
) {
if(this.userProfile.currentUser) {
console.log('constructor MomentsPage');
this.enrolledLis = this.afDB.list('/userEnrollments/'+this.userProfile.currentUser.uid).snapshotChanges()
.map( res => {
let enrolled = res;
let that = this;
return enrolled.map(key =>
that.courseService.getCourseDetail(key.key).snapshotChanges()
.map(snap =>
({ key: snap.key, ...snap.payload.val() } )
)
)
}
);
}
}
goToTopicsFeed(course: any) {
this.navCtrl.push(MomentsFeedPage, {
courseId: course.key, courseName: course.name, coursePic: course.coursePic
});
}
ionViewDidLoad() {
console.log('ionViewDidLoad MomentsPage');
}
}
And this is the code for the view
<ion-header>
<ion-navbar>
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>Moments</ion-title>
</ion-navbar>
</ion-header>
<ion-content no-padding fullscreen parallax-header>
<div class="header-image" style="background-image:url('./assets/imgs/lists/wishlist-1.jpg')">
<h1>Moments</h1>
</div>
<div class="main-content">
<ion-list #enrolledList>
<ion-item-sliding *ngFor="let course of enrolledLis | async" [attr.track]="(course|async)?.degree | courseTrackPipe ">
<button ion-item (click)="goToTopicsFeed(course)" >
<ion-thumbnail item-start>
<img [src]="(course|async)?.coursePic || './assets/imgs/Film-set-greyscale.jpg'" alt="Course profile pic">
</ion-thumbnail>
<h2>{{(course|async)?.name}}</h2>
<h3>{{(course|async)?.degree}}</h3>
<p>Topics info: #topics {{(course|async)?.topicsCount}} activity...</p>
</button>
</ion-item-sliding>
</ion-list>
</div>
</ion-content>
Here you can see the behaviour:
OK. I'll answer to myself: nothing wrong with the code, maybe I tested wrong. Anyway, there was something not so good in the code: returning async Observables may lead to some problems in the (click) action. Those can be solved using a *ngIf="course" block to make sure the object is got during runtime.