问题
I'm using Angular 4 for my client application.
The getCustomer() function in customer.service calls an API to get data. This function is Observable.
This function needs an access token to be able to call the API. And the access token can be gotten from getAccessToken() function in auth.service.
But getAccessToen() is async. How can we get value from the async function?
Note that getCustomer() must be Observable so that I can map data from response and bind to members of customer.component.
auth.service.ts
import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class AuthService {
private tokenEndpoint = "http://localhost:9000/connect/token";
private clientId = "testclientid";
private clientSecret = "testsecret";
constructor(private http: Http) { }
getAccessToken() : Observable<any> {
let credential = "Basic " + btoa(`${this.clientId}:${this.clientSecret}`);
let body = "grant_type=client_credentials&scope=testscope";
let headers = new Headers();
headers.set("Content-Type", "application/x-www-form-urlencoded");
headers.set("Authorization", credential);
return this.http.post(this.tokenEndpoint, body, { headers: headers })
.map(result => {
let data = result.json();
return data.access_token || "";
});
}
}
customer.service.ts
import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { Customer } from './customer';
import { Address } from './customer';
import { ResourceData } from './customer';
import { ResourceAttributes } from './customer';
import { CustomerResource } from './customer';
import { ResourceCollection } from './customer';
import { AuthService } from '../auth/auth.service';
@Injectable()
export class CustomerService {
private customersUrl = "http://localhost:60001/api/v1/customers";
constructor(private http: Http, private authService: AuthService) { }
getCustomer(id: string): Observable<CustomerResource> {
let accessToken = this.authService.getAccessToken().subcribe(
// how to get accessToken from authService because subcribe is async?
);
let headers = addAccessTokenToHeader(accessToken);
let url = `${this.customersUrl}/${id}`;
return this.http.get(url, { headers: headers })
.map(result => {
return result.json() as CustomerResource;
})
.catch((error) => {
console.log(error);
return Observable.throw(error);
});
}
private addAccessTokenToHeader(accessToken: string): Headers {
let headers = new Headers();
headers.set("Authorization", `Bearer ${accessToken}`);
return headers;
}
}
customer-detail.component.ts
showCustomer(id: string) {
this.modalTitle = "Update PL customer";
this.buttonSaveTitle = "Update";
this.customerService.getCustomer(id)
.subscribe(customer => {
this.mapFromResource(customer.data);
this.customerModal.show();
});
}
private mapFromResource(data: ResourceData) {
this.customerId = data.id;
this.reference = data.attributes.reference;
this.lastName = data.attributes.lastName;
this.middleName = data.attributes.middleName;
this.firstName = data.attributes.firstName;
}
// this.customerId, this.reference are the members of customer.component. They are binding on UI.
回答1:
Off the top of my head, in your customer.service.ts
you can chain method calls with something like this:
getCustomer(id: string): Observable<CustomerResource> {
this.authService.getAccessToken()
.map((accessToken) => {
let headers = addAccessTokenToHeader(accessToken);
let url = `${this.customersUrl}/${id}`;
return this.http.get(url, { headers: headers })
// rest of the code
});
If it doesn't work, try replacing .map
with .switchMap
.
回答2:
I'm using flatMap and it works now. Thank you very much for your suggestions @AJT_82
来源:https://stackoverflow.com/questions/47113703/angular-4-how-can-get-value-synchronously-from-an-http-request-in-another-http