サーバーにhttpリクエストを行い、データを取得するObservableを返すサービスがあります。このデータを使用したいのですが、常にundefined
になります。どうしたの?
サービス:
@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({...})
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!
}
}
Angular/javascriptでhttp呼び出しを行うことは非同期操作です。したがって、http呼び出しを行うと、この呼び出しを終了し、別のスレッドで次の行の実行を開始する新しいスレッドが割り当てられます。それが未定義の値を取得している理由です。これを解決するには、以下の変更を行ってください
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //<-this become synchronous now
});
テンプレートでのみmyEventsを使用する場合は、 asyncPype を使用できます。
ここにasyncPypeとAngular4 HttpClientを使用した例 https://stackblitz.com/edit/angular-rhioqt?file=app%2Fevent.service.ts
ここで問題は、this.myEvents
をsubscribe()
から初期化することです。これは、console.log()
ブロックからsubscribe()
ブロックを実行している間に非同期ブロックです。したがって、this.myEvents
が初期化される前にconsole.log()
が呼び出されます。
Console.log()コードもsubscribe()内に移動してください。完了です。
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents);
});
}
angular process asyncのため、結果は未定義です。以下のように試すことができます:
async ngOnInit(){
const res = await this.es.getEventList();
console.log(JSON.stringify(res));
}
オブザーバブルは遅延しているため、値を取得するにはサブスクライブする必要があります。コードで適切にサブスクライブしましたが、同時に 'subscribe'ブロックの外部に出力を記録しました。それが「未定義」である理由です。
ngOnInit() {
this.es.getEventList()
.subscribe((response) => {
this.myEvents = response;
});
console.log(this.myEvents); //Outside the subscribe block 'Undefined'
}
したがって、サブスクライブブロック内でログに記録すると、応答が適切に記録されます。
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //Inside the subscribe block 'http response'
});
}
また、応答をjson出力にマッピングしてください。それ以外の場合は、プレーンテキストを返します。これは次のように行います。
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)=>{ return res.json();}) <!-- add call to json here
.catch((err)=>{return err;})
}