Search code examples
jsonangularrxjsangular2-http

Using Angular Observers to fetch data over a network


I'm working on an Angular app that contains a list of (financial) Trades that a user can add to. This has been going well, and I'm trying to switch over from a static list provided by a service to trying to fetch the data from a local Node.js server. I'm using an observer to asynchronously fetch the list of trades.

I've been following along with Angular's HTTP tutorial and the associated plunker. However, even though I can see the data coming from the server, I'm having trouble using the .subscribe() method to get a useful set of data out of it.

Here's my service which connects to the node server:

   @Injectable()
export class TradeService {
  private url = '...';  // URL to web API
  tradeArray: Trade[] = [];
  constructor(private http: Http) { }
  //-----------GETTERS---------------//
  getTradeObservable(): Observable<Trade> {
    return this.http.get(this.url)
      .map(this.extractData)
      .catch(this.handleError);
  }

  private extractData(res: Response) {
    let body = res.json();
    console.log("body:" + body);
    console.log("Entire Body.trades: " + body.trades);
    return body.trades;
  }

  getTrades(): any {
    this.getTradeObservable()
      .subscribe(
          trade => this.tradeArray.push(trade));
    return this.tradeArray;
  }

And here are the relevant portions the node server itself:

var TRADES = { "trades": [
   {"id": 0, "cust": "Ben", "hasSub": true,
       "subcust": "Rigby", "type": "s", "security": "001", "ticket": "99"},
   ...
   {"id": 9, "cust": "Uber Bank", "hasSub": true,
            "subcust": "Lil Bank", "type": "p", "security": "456", "ticket": "56"}
]};


////////////Get Requests/////////////////

//this route returns all data in JSON format
app.get('/', function(req, res) {
    res.send(JSON.stringify(TRADES));
    });

And the expected output from getTrades:

[
   {id: 0, cust: "Ben", hasSub: true,
       subCust: "Rigby", type: "s", security: '001', ticket: '99'},
   ...
   {id: 9, cust: "Uber Bank", hasSub: true,
            subCust: "Lil' Bank", type: "p", security: '456', ticket: '56'},
];

And one of the places the service is injected into and called:

export class SubmittedComponent {
  constructor(private tradeService: TradeService) { }

  //initally show all trades
  rows = this.tradeService.getTrades();
...

I can see in the browser console that 'entire body.trades' is a full list of the data I want, but it seems subscribe is not pushing them into tradeArray, which ends up undefined.

Thank you for your time.


Solution

  • So I suppose that you are calling getTrades() from one of your components. If this is the case, this is what will happen:

    • The request will be sent
    • The request will be processed in the background asynchronously
    • The method will not wait for the request to be resolved and will return the current value of tradeArray, which is []

    To avoid this, you could refactor you components so that they invoke the getTradeObservable() method an subscribe to the returned Observable.

    UPDATE: Another option would be to refactor you service to use a Subject', and expose it to your components through anObservable`.

    UPDATE: Assuming that you have the following definition for Trade

    export interface Trade{
       id: number;
       cust: string;
       hasSub: boolean;
       subCust: string;
       type: string;s
       security: string;
       ticket: string;
    }
    

    You could try the following approach

    class TestComponent {
      data: Trade[];
      // inject service in component
    
      getData(){
         this.service.getTradesObservable().subscribe(data => this.data = data);
      }
    }
    

    And change the definition of getTradesObservable to :

    getTradeObservable(): Observable<Trade[]> {
        return this.http.get(this.url)
          .map(this.extractData)
          .catch(this.handleError);
      }