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

// Import RxJs required methods
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch'

@Injectable()
export class EquipmentService{
    data: any;
    constructor(private http:Http){

    }
    getDefaultEquipment(){
        this.http.get('./app/SaveData/equipmentTest.json')
            .map((res:Response) => res.json())
            .subscribe(data => { this.data = data},
                err => console.error(err),
                () => console.log(this.data));
    }
}

Reading data from a file, The important bit is getDefaultEquipment().

If you see the last console.log(this.data) the data is correct, it's exactly what I need. But if I return this.http.get(... () => {return this.data}) i get undefined. How do I get at and return this.data??

Obviously if I write another return such as the following, the observable hasn't completed yet, so it will return the empty data: any.

//clearly won't work because the get hasn't returned yet
getDefaultEquipment(){
    this.http.get(...data => {this.data = data}...);
    return this.data;
}
3
  • Just return your observable. you do not need to convert an asynchronous call into a syncronous call. Commented Nov 22, 2016 at 22:30
  • You can't return data. Don't subscribe. Just return the observable. The caller will be the one that subscribes, and will get the data in the callback function passed to subscribe(). Commented Nov 22, 2016 at 22:31
  • Awesome. That did the trick. Added subscribe method to the caller in my equipment component this.equipmentService.getDefaultEquipment().subscribe( stuff => {console.log(stuff)}, ); Thanks. Commented Nov 22, 2016 at 22:37

1 Answer 1

4

The following would be my take on it. Untested but the concept is solid. This would save you a lot of boilerplate code because of the async pipe which basically eats Observables. If you need to do some transformations then that would be possible also before returning the observable. You could either do that in the service, or you could do it in the component. Just remember on thing about Observables, be sure to use the .share() operator if you have multiple subscribers, or else you would execute (in this case) the http.get once for each subscriber. The same goes for the .do operator which can come in handy, but also acts like a subscriber.

I would recommend reading up on RxJs and take a look at the example from angulars website concerning usages of the async pipe.

The Angular AsyncPipe is an interesting example of an impure pipe. The AsyncPipe accepts a Promise or Observable as input and subscribes to the input automatically, eventually returning the emitted value(s).

equipment.service.ts

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

export interface Equipment {
  name: string;
  id: string;
}

@Injectable()
export class EquipmentService {

  constructor(private http:Http){}

  public getDefaultEquipment(): Observable<Equipment[]> {
    return this.http
    .get('./app/SaveData/equipmentTest.json')
    .map((res:Response) => res.json());
  }
}

equipment-list.component.ts

import { Component, OnInit } from "@angular/core";
import { EquipmentService, Equipment } from "./services/equipment.service";
import { Observable } from 'rxjs/Rx';

@Component({
  selector: 'equipment-list',
  templateUrl: './equipment-list.component.html',
  styleUrls: ['./equipment-list.component.css'],
  providers:[
     EquipmentService
  ]
})
export default class EquipmentComponent {

    constructor(private service: EquipmentService) {}

    public get equipment():Observable<Equipment[]> {
        return this.service.getDefaultEquipment();
    }
}

equipment-list.component.html

<ul>
    <li *ngFor="item of (equipment | async)>
       <span>{{item.id}}</span>
       <span>{{item.name}}
    </li>
</ul>
Sign up to request clarification or add additional context in comments.

6 Comments

Answers are best when there is some explanation with them. Simply saying "do this" doesn't help us to understand why it works that way and as such doesn't help us if a similar situation arises.
Sorry. had a missclick and posted before the explanation was complete.
@abdavid 's answer is correct and good, although I would not write .map((res:Response) => res.json()); to a service, because I want my components to react to the response: read headers, status code, etc.
If you have a component that needs to react to spesific headers then one would move the .map((res:Response) => res.json()); where needed. For this example though it should suffice, but thank you for clarifying that.
This is really insightful, and has helped clarify a few implementation questions I had. Thanks for the res:Response => res.abdavid() ;)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.