First, this is an Angular2 app. I am just starting out building with Angular2 and Firebase. I am using AngularFire2 as well. I know that my service is working, because I can print out the blog.title
just fine right after subscribing. But that is the only place I can get access to the results. Everywhere else it is giving me an undefined
error. Whether I use it in the template with {{}} or in the class, I get the same same result. I am not sure what I am doing wrong. I am also new to observables.
export class BlogEditComponent implements OnInit {
blogForm: FormGroup;
blog$: FirebaseObjectObservable<Blog>;
blog: Blog;
constructor(private route: ActivatedRoute,
private router: Router,
private fb: FormBuilder,
private blogService: BlogService) { }
ngOnInit() {
this.isNew = false;
this.blog$ = this.blogService.getBlogFromId(this.route.snapshot.params['id']);
this.blog$.subscribe(snapshot =>{
this.blog = snapshot;
console.log(this.blog.title); //prints out fine
});
console.log(this.blog.title); //throws error here
}
}
BlogService
getBlogFromId(id: String): FirebaseObjectObservable<Blog> {
return this.af.database.object('blogs/' + id);
}
This is the expected behavior: the callback runs at a different time than the code around it.
It is easiest to see this you ignore the actual values and just log some static strings:
ngOnInit() {
this.blog$ = this.blogService.getBlogFromId(this.route.snapshot.params['id']);
console.log("before subscribing");
this.blog$.subscribe(snapshot =>{
console.log("in callback");
});
console.log("after subscribing");
}
When you run this, the logging will be:
before subscribing
after subscribing
in callback
This is probably not the order that you naturally expected. But it is the documented behavior: since the data is being loaded from a remote server, it may take some time to get back to you. While it is being loaded, the code after the subscribe
call continues.
I often find it easiest to work within this by reframing my problem. Normally you'd say "first get the blog post, then print the title". But now reframe it to "start getting the blog post; when you get it, print the title".
In code this means that you mode all the code that needs the title into the callback, like your first logging statement. So:
ngOnInit() {
this.isNew = false;
this.blog$ = this.blogService.getBlogFromId(this.route.snapshot.params['id']);
this.blog$.subscribe(snapshot =>{
this.blog = snapshot;
console.log(this.blog.title);
});
}
This also has the advantage that the blog title will print if the blog title changes, which is one of the staples of the Firebase Realtime Database.