1

I'm newbie in Angular2, and need help with Observables.

I have web-app, that get some data from remote resource and show it to users.

The problem is that I should get data using http, store it locally and after that use by other components.

I've tried next scheme:

data.ts

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class Airports {
    private airportsUrl: string;
    private cities: any;
    private countries: any;
    private routes: any;
    private rawData: Observable<any>;
    private errorMessage: any;

    constructor(private http: Http) {
        this.airportsUrl = '';
    }

public get Cities() {
    this.serverData.publishLast().refCount().subscribe(
        data => this.cities = JSON.stringify(data)
    );
    return this.cities;
}

public get Countries() {
    this.serverData.publishLast().refCount().subscribe(
        data => this.countries = JSON.stringify(data)
    );
    return this.countries;
}

public get Routes() {
    this.serverData.publishLast().refCount().subscribe(
        data => this.routes = JSON.stringify(data)
    );
    return this.routes;
}

private init() {
    this.serverData
        .subscribe(
            data => this.rawData = data,
            error =>  this.errorMessage = <any> error
        );
}
private get serverData() {
    return this.http
        .get(this.airportsUrl)
        .map(this.parseData)
        .catch(this.handleError);
}
private parseData(res: Response) {
    let body = res.json();
    return body;
}
private handleError (error: any) {
    let errMsg = (error.message) ? error.message :
    error.status ? `${error.status} - ${error.statusText}` : 'Server error';
    console.error(errMsg);
    return Observable.throw(errMsg);
}
}

controler.ts

import '../../../public/css/styles.css';
import { Component, OnInit } from '@angular/core';

import { Airports } from './../data/data';

@Component({
    providers: [Airports],
    selector: 'destination-selector',
    styleUrls: ['./../views/view.cityselector.css'],
    templateUrl: './../views/view.cityselector.html',
})
export class CitySelector implements OnInit {
    private cities: any;
    private countries: any;
    private routes: any;

    constructor(private airports: Airports) { }

    public ngOnInit() {
        this.cities = this.airports.Cities;
        this.countries = this.airports.Countries;
        this.routes = this.airports.Routes;
    }
}

view.cityselector.html

<main>
    <div>Cities: {{ cities }}</div>
    <div>Countries: {{ countries }}</div>
    <div>Routes: {{ routes }}</div>
</main> 

But, with this scheme I call http 3 times (instead 1), and this value {{ cities }} is undefined

So, how I can get data from http, stroe it to some local variable, and use local data after that, instead calling always new http

Sergiy Voznyak
  • 111
  • 1
  • 6

1 Answers1

0

I think this is because http.get in Angular2 returns an observable that does not actually get any data until you call subscribe on it. Then each time you are calling subscribe on it you are making a new http request. I think instead you should subscribe to your http.get immediately and set it once in a variable in your service. Then have your services public functions return an observable of the value of that variable.

This article by Cory Rylan was very helpful and got me started on the data service that I was working on.

I did something like this where my service was managing an array of data for the rest of the app. Then in the components that used the data I would import the DataService and subscribe to the return value of dataService.getData()

@Injectable
export class DataService {
  constructor(private http: Http){
    this.loadData();
    }
  private _url = 'http://yoururlhere.com:3000/api/path';
  public _appData$: BehaviorSubject<any[]> = new BehaviorSubject([]);
  private appData:any[] = [];

  loadData() {
    console.log('Making HTTP request, loading data...');
    this.http.get(this._url).map(this.extractData).subscribe(
      data => {
        this.appData = data;
        this._appData$.next(data);
      },
      error => {
        console.log(error);
      }
    );
  }

  addData(newData){
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({
      headers: headers
    });
    
    this.http.post(this._url, newData, options).map(this.extractData).subscribe(data => {this.appData.push(data); this._appData$.next(this.appData);});

   }
  getData(){
    return Observable.from(this._appData$);
    }

  private extractData(res: Response) {
    let body = res.json();
    return body || {};
  }
}
Frank
  • 114
  • 6