1

In my project, I use Observables in service to hold data taken from DB. So I subscribe to it in my main component.

In search.service, the data retrieving function

  getData(){
    return new Observable(subscriber => {
      this.db.find({}, function(err, docs) {
        if (err) subscriber.error(err);
        subscriber.next(docs);
      });
    })
  }

In main component

  getData(){
    this.searchService.getData().subscribe(
      data => {
        this.datum = data;
        console.log(this.datum)},
      err => console.log("E", err)
    );
    console.log(this.datum);
  }

  ngOnInit(){
    this.getData();
  }

Here are the results I get in the console

Results in the console

From this I understand that while in the context of .subscribe() method, property datum is assigned the contents of database, but outside of it, it is still undefined. I don't get why it happens, or how to display the contents of DB. All the tutorials I've found suggest that after I subscribe to observable and assing in the subscription method the property of my component to result passed in observable, everything should stay this way and I should be able to display it easily in the component.

Been bashing my head against this for a month or so and had no luck with articles on observables. Seems like I get the principles but, no matter what, can't put them to use.

Any tips would be greatly appreciated.

(I don't want to resort to using promises, because observables seem a little more general in terms of their applicability and it seems that learning them is a very potent skill to have)

EDIT

The html template for the component.

<!--The whole content below can be removed with the new code.-->
<div style="text-align:center">
  <h1>
    Welcome to {{title}}!!
    Data: {{datum}}
  </h1>

EDIT 2

View

View

Ivan Bespalov
  • 147
  • 1
  • 12
  • db.find() is **asynchronous**. That's why it doesn't return the values it finds, but instead takes a callback as argument, to notify you when the data is available. So you can't expect to have the data immediately after subscribing to your observable. You'll have them (as the logs show) only when the observer is called. Why it's not displaying is another matter. Post the template of your component. – JB Nizet Sep 08 '17 at 05:46
  • I get this. But why then the results of db.find() stored in the property datum? In the demplate I have the interpolation syntax like this {{(datum | async)}}, but it doesn't display anything – Ivan Bespalov Sep 08 '17 at 05:49
  • I've marked this as duplicate. If you think it's not, please comment and I'll cancel it – eko Sep 08 '17 at 05:54
  • It's very similar, but the difference is that I already get that to have my result logged I have to call the log function inside the subscribe() method, but don't know how to display the results after assigning as it seems that property storing the results remains undefined – Ivan Bespalov Sep 08 '17 at 05:59
  • How do you try to display it? If it's like `{{(datum | async)}}`, you are using it wrong because `async` is a pipe for observables. Remove the pipe and simply use it like `{{ datum }}` – eko Sep 08 '17 at 06:00
  • This is how I try to display it. I've tried just {{datum}} and {{data}}. Neither worked – Ivan Bespalov Sep 08 '17 at 06:02
  • datum is not defined in the component, the result of GetData(), variable "data" in subscribe() method is an array – Ivan Bespalov Sep 08 '17 at 06:05
  • You have a comment with `ngFor` for your html but now you are saying you don't in your edit. This seems like an xy problem – eko Sep 08 '17 at 06:14
  • @echonax Don't know if I understand what you are saying, In my comment I said that I tried the `ngFor` implementation as well as with and without `async` pipe, and none of them did work – Ivan Bespalov Sep 08 '17 at 06:17

2 Answers2

2

[Follow the numbers in comments; they represent order of execution]

getData(){
    this.searchService.getData()
        .subscribe( //1. subscrube just registers what will happen when data comes and immediately goes to next call
            this.successHandle.bind(this),//3. this will run only when data comes which might be a year from subscription
            err => console.log("E", err)
        );
    console.log(this.datum); //2. runs immediately after subscribe
  }

successHandle(data){
    this.datum = data;
    console.log(this.datum) //4. logs data when it comes
}

your line 2. logs 'undefined' as there is no data yet at that point. you are just subscribed, but data will come in future

eko
  • 39,722
  • 10
  • 72
  • 98
dee zg
  • 13,793
  • 10
  • 42
  • 82
  • Thank you, it's a little clearer now, but do I need a separate function in the component to do the assigning? The goal is to be able to use the data I get from DB to populate the template. Now the interpolation in the template does nothing – Ivan Bespalov Sep 08 '17 at 05:54
  • 1
    This answer is wrong because `this` inside the `successHandle` method won't refer to the component hence `this.datum` will be undefined. – eko Sep 08 '17 at 05:59
  • well, there you have several options, from `async` pipe to manual resolving. for start, i would suggest you check this in docs: https://angular.io/tutorial/toh-pt4#async-services-and-promises – dee zg Sep 08 '17 at 05:59
  • @echonax, what will `this`refer to if not the component? – dee zg Sep 08 '17 at 06:05
  • It will refer to the `successHandle` methods instance. You should read: https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback – eko Sep 08 '17 at 06:06
  • oh, ok ok, of course...but that's a whole another point...point here was to illustrate the flow blocks. – dee zg Sep 08 '17 at 06:56
  • @deezg yes the flow is correct of course but if the OP tries to execute this it will not work. I'll edit it for you (I didn't downvote btw) – eko Sep 08 '17 at 08:13
  • no problem, of course, you are completely right. thanks for edit! – dee zg Sep 08 '17 at 08:27
0

Here you are doing Asynchronous call, and console.log(this.datum); outside your subscribe in Component will run while your data is being fetched from DB, and when it is done, then console.log(this.datum) in your subscribe will run. That is the whole story of Observables and callBacks..

Wasif Khan
  • 956
  • 7
  • 25