Angular 4 - How can get value synchronously from an http request in another http request?

匆匆过客 提交于 2020-04-06 01:59:29

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!