Cameron Gilbert Cameron Gilbert - 3 months ago 79
TypeScript Question

Using async/await function in angular 2

I am trying to figure out how to use async/await in my angular classes.
I have a PostService that gets posts from an api but is reliant on the AreaService so that PostService knows which area to get the post from. Can't quite figure out how to tell my angular class PostService to wait on data from my AreaService.
A correct response from AreaService would be the string "fun". PostService would then use this fun string in the this.areas array to display posts to the user from the currently selected area
The current error is: Uncaught (in promise): Error: Error in :0:0 caused by: Cannot read property 'name' of undefined

postservice

import { Injectable, OnDestroy } from '@angular/core';
import { Http, Headers, RequestOptions, Response } from '@angular/http';
import { Observable} from 'rxjs';
import 'rxjs/add/operator/map';

import { AuthenticationService, AreaService, MessageService} from './index';
import { Post, Area} from '../_models/index';

@Injectable()
export class PostService {
areas: Area[] = [];
constructor(
private http: Http,
private authenticationService: AuthenticationService,
private areaService: AreaService,
private messageService: MessageService
) {

}

getPosts(): Observable<Post[]> {
this.areaService.getAreas().subscribe(area => { this.areas = area;});

// add authorization header with jwt token
let headers = new Headers();
headers.append('Authorization','token ' + this.authenticationService.token);

headers.append('Content-Type', 'application/json');
let options = new RequestOptions({

headers: headers
});

// get posts from api
return this.http.get('http://localhost:8000/areas/'+ this.areas[0].name +'/', options)
.map((response: Response) => response.json());

}
}


areaservice

import { Injectable } from '@angular/core';
import { Http, Headers, RequestOptions, Response } from '@angular/http';
import { Observable, Subject } from 'rxjs';
import 'rxjs/add/operator/map';

import { AuthenticationService, MessageService } from './index';
import { Area } from '../_models/index';

@Injectable()
export class AreaService {
public areas: Observable<Area[]> ;
subject:Subject<Area[]> = new Subject();
public currentArea: string = "fun";
constructor(
private http: Http,
private authenticationService: AuthenticationService,
private messageService: MessageService) {
}

getAreas(): Observable<Area[]> {

// add authorization header with jwt token
let headers = new Headers();
headers.append('Authorization','token ' + this.authenticationService.token);

headers.append('Content-Type', 'application/json');
let options = new RequestOptions({
headers: headers
});
// get areas from api
return this.http.get('http://localhost:8000/areas/', options)
.map((response: Response) => response.json());

// this.areas = response.json();
// console.log("h");
// this.messageService.sendMessage(this.areas[0].name);


//this.messageService.sendMessage(this.areas[0].name);
}
}


area.ts

import { Injectable } from '@angular/core';
@Injectable()
export class Area{
name:string;
currentArea:number = 1;

constructor(name:string) {
this.name = name;
}

public static createEmptyrea():Area{
return new Area("");
}
setArea(val:number) {
this.currentArea = val;
}

}


incoming json from /areas/

[
{
"name": "fun"
},
{
"name": "information"
}
]

Answer Source

You don't need async/await if you're working with observables. You need to use mergeMap operator for rxjs@5 or flatMap for rxjs@4:

getPosts(): Observable<Post[]> {
    // subscribe until the area is available
    return this.areaService.getAreas().mergeMap(area => {

        // add authorization header with jwt token
        let headers = new Headers();
        headers.append('Authorization', 'token ' + this.authenticationService.token);

        headers.append('Content-Type', 'application/json');
        let options = new RequestOptions({

            headers: headers
        });

        // use the area to get the response
        return this.http.get('http://localhost:8000/areas/' + area.name + '/', options)
            .map((response: Response) => response.json());
    });
}