1

In my project I have a service that loads data from NeDB. For this purpose I have a method getData(). In my component, using ngOnInit() hook I call this method.

Here's where the problem lies.

If getData() uses promises everything works as intended and on startup of my app I have the result of query to a database loaded and displayed.

getData() using promises

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Rx';

import * as Datastore from 'nedb';
import * as path from 'path';

@Injectable()
export class SearchService {
db: any;
  constructor() {
    this.db = new Datastore( {
      filename: path.resolve('src/assets/db.json'),
      autoload: true,
    });
  }

  getData(){
    return new Promise((resolve, reject) => {
      this.db.find({}, (err, docs) => {
        if (err) reject(err);
        resolve(docs);
      });
    })
  }

}

But if I try to do this using observables nothing is loaded and displayed (the result passed to subscriber is undefined).

getData() using observables

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

App Component

import { Component, OnInit } from '@angular/core';
import { SearchService } from './search_service/search.service';
import { Observable } from 'rxjs/Observable';
import * as Datastore from 'nedb';
import * as electron from 'electron';
import * as path from 'path';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [SearchService]
})
export class AppComponent implements OnInit {
  title = 'app';
  datum;
  res;
  constructor(private searchService: SearchService){ }
  ngOnInit(){
    this.getData();
    this.res = this.searchService.getDataObs();
  }

  getData(){
    this.searchService.getData().then(res => this.datum = res);
  }
}

What I get in my app on startup enter image description here

Any tips on why is this happening? I don't think this is normal behaviour and presume that it has something to do with the way I create observable. I've read about bindCallback() operator, functionality of which seems to be what I need here, since db.find() is a callback function, but I wasn't able to implement it correctly.

Sorry for the messy code and thanks in advance

EDIT - HTML

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

EDIT - If I add getDataObs() method to a button, or call it 100 or so ms after the startup it returns the query as intended.

Ivan Bespalov
  • 147
  • 1
  • 12
  • did you use the `json` filter in the html – Sachila Ranawaka Sep 18 '17 at 07:04
  • @SachilaRanawaka not yet. I'm just trying to make it work right now. It doesn't matter how it looks. But I've added HTML to question for clarity – Ivan Bespalov Sep 18 '17 at 07:06
  • you need to use something like `{datum | json}` in the html template and if possible you can also check the value by console logging – Rahul Singh Sep 18 '17 at 07:06
  • @RahulSingh problem is not in the value I recieve but in that I don't recieve anything from `getDataObs()` method if it's called on startup – Ivan Bespalov Sep 18 '17 at 07:08
  • @JBNizet in the template I use `async` pipe. It does the subscription under the hood. If I, for example, would rewrite `getDataObs()` to return observable with simple `subscriber.next('Hello')` the Hello message would appear in the view. I didn't want to complete my observable because I thought of it as of stream of find results coming from the service, but, now I believe that's not the right way, Currently, adding `subscriber.complete()` to observable either in `db.find()` function or plainly in the body does nothing – Ivan Bespalov Sep 18 '17 at 07:52

1 Answers1

0
this.res = this.searchService.getDataObs();

This expression simply is returning an Observable instance to "res", what you might need to do is subscribe to this Observable and set the response in the success callback. As you mentioned it works fine when you trigger it after a few ms as the call is complete by then.

this.searchService.getDataObs().subscribe(res => this.res = res)

An observable same like promise runs asynchronously separate from your main thread.

Naresh Pingale
  • 246
  • 1
  • 6