How do I return the response from an Observable/http/async call in angular? Ask Question

How do I return the response from an Observable/http/async call in angular? Ask Question

I have service which returns an observable which does an http request to my server and gets the data. I want to use this data but I always end up getting undefined. What's the problem?

Service:

@Injectable()
export class EventService {

  constructor(private http: Http) { }

  getEventList(): Observable<any>{
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });

    return this.http.get("http://localhost:9999/events/get", options)
                .map((res)=> res.json())
                .catch((err)=> err)
  }
}

Component:

@Component({...})
export class EventComponent {

  myEvents: any;

  constructor( private es: EventService ) { }

  ngOnInit(){
    this.es.getEventList()
        .subscribe((response)=>{
            this.myEvents = response;
        });

    console.log(this.myEvents); //This prints undefined!
  }
}

I checked How do I return the response from an asynchronous call? post but couldn't find a solution

ベストアンサー1

Reason:

The reason that it's undefined is that you are making an asynchronous operation. Meaning it'll take some time to complete the getEventList method (depending mostly on your network speed).

So lets look at the http call.

this.es.getEventList()

After you actually make ("fire") your http request with subscribe you will be waiting for the response. While waiting, javascript will execute the lines below this code and if it encounters synchronous assignments/operations it'll execute them immediately.

So after subscribing to the getEventList() and waiting for the response,

console.log(this.myEvents);

line will be executed immediately. And the value of it is undefined before the response arrives from the server (or to whatever that you have initialized it in the first place).

It is similar to doing:

ngOnInit(){
    setTimeout(()=>{
        this.myEvents = response;
    }, 5000);

    console.log(this.myEvents); //This prints undefined!
}

**Solution:** >So how do we overcome this problem? We will use the callback function which is the `subscribe` method. Because when the data arrives from the server it'll be inside the `subscribe` with the response.

So changing the code to:

this.es.getEventList()
    .subscribe((response)=>{
        this.myEvents = response;
        console.log(this.myEvents); //<-- not undefined anymore
    });

will print the response.. after some time.


**What you should do:**

There might be lots of things to do with your response other than just logging it; you should do all these operations inside the callback (inside the subscribe function), when the data arrives.

Another thing to mention is that if you come from a Promise background, the then callback corresponds to subscribe with observables.


**What you shouldn't do:**

非同期操作を同期操作に変更しようとしないでください (変更できるわけではありません)。非同期操作がある理由の 1 つは、ユーザーが操作の完了を待たずに、その間に他の操作を実行できるようにするためです。非同期操作の 1 つが完了するまでに 3 分かかると仮定すると、非同期操作がなければ、インターフェイスは 3 分間フリーズします。


おすすめの読み物:

この回答の元の出典は以下です:非同期呼び出しから応答を返すにはどうすればいいですか?

しかし、Angular2 のリリースでは TypeScript と Observables が導入されたので、この回答では Observables を使用して非同期リクエストを処理する基本をカバーできると思います。

おすすめ記事