Angular5 HttpClient,在 GET api 调用后设置变量

o.o*_*o.o 5 http typescript angular-http angular

MySharedService我有一个多个组件使用的服务(我们称之为)。在内部MySharedService,我调用了另一个进行 API 调用的服务。MySharedService保存一个在我调用后分配的 JavaScript 对象GET

我的问题是我的组件依赖该 JavaScript 对象在其构造函数中设置它们的值。当由于 API 调用尚未完成而导致 JavaScript 未定义时,我该如何设置它们的值?这是一个示例:

API服务

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '@angular/common/http';
/* Other imports */

@Injectable()
export class ApiService {

    constructor(private http: HttpClient) { }

    getTestData(): Observable<MyDataInterface> {
        const API_URL = 'some_url_here';
        return this.http.get<MyDataInterface>(API_URL, { observe: 'response' });
    }
}
Run Code Online (Sandbox Code Playgroud)

我的共享服务

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
/* Other imports */

@Injectable()
export class MySharedService {

    myData: MyDataInterface;

    constructor(private apiServie: ApiService) {
        this.apiService.getTestData().subscribe((response) => {
            this.myData = { ...response.body };
            console.log(this.myData);
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

测试组件

import { Component, OnInit } from '@angular/core';
import { MySharedService } from '../../../services/myshared.service';
/* Other imports */    

@Component({
    selector: 'app-test',
    templateUrl: './test.component.html',
    styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {

    name: string;
    /* Other variables here. */

    constructor(private mySharedService: MySharedService) {
        // Error here because myData has not been populated, yet.
        this.name = this.mySharedService.myData.name;
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,当我尝试从对象访问数据时,问题发生在我的组件内部,myData因为它尚未填充(最终会console.log()在几秒钟后打印出数据)。我应该如何获取这些值?我只想调用一次其余服务并将对象保存在其中MySharedService,然后让我的所有组件都使用该对象。

cyb*_*e92 5

你应该使用BehaviorSubject

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
/* Other imports */

@Injectable()
export class MySharedService {

    myData: BehaviorSubject<MyDataInterface> = new BehaviorSubject(null);

    constructor(private apiServie: ApiService) {
        this.apiService.getTestData().subscribe((response) => {
            this.myData.next({ ...response.body });
            console.log(this.myData.getValue());
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

在组件构造函数中进行订阅是一种不好的做法,请改用ngOnInit生命周期挂钩。

export class TestComponent implements OnInit {

    name: string;
    /* Other variables here. */

    constructor(private mySharedService: MySharedService) {
    }

    ngOnInit() {
        this.mySharedService.myData.subscribe((data: MyDataInterface) => { 
            if (data)
                this.name = data.name;
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

网络调用只会进行一次,数据将缓存在 中BehaviorSubject,所有组件都会订阅该数据。

现在为什么使用 aBehaviorSubject而不是 an Observable?因为,

  • 订阅时BehaviorSubject返回最后一个值,而常规可观察对象仅在收到 onnext 时触发。

  • 如果您想BehaviorSubject在不可观察的代码(无需订阅)中检索 的最后一个值,您可以使用该getValue()方法。