Cannot access firebaseObjectObservable outside of

2019-07-29 23:55发布

问题:

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);
}

回答1:

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.