0

我正在使用独立的 TypeScript 类调用我的后端服务。console.log在实例化我的共享类的实例时,我能够捕获数据。但是,我无法在我的角度组件中访问该类的本地属性和方法。

这是我的组件:

import { Component, OnInit } from '@angular/core';
import { ProjectService } from '../shared/projectService';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-about',
  templateUrl: './about.component.html',
  styleUrls: ['./about.component.css']
})

export class AboutComponent implements OnInit {

  projects: any;
  windowWidth: number;
  service: ProjectService;

  constructor(private httpClient: HttpClient) { 
    this.service = new ProjectService(this.httpClient);
    //  returns as undefined
    console.log(this.service.getAllProjects());   
  }

  ngOnInit() {
    this.windowWidth = window.innerWidth;
  }

}

这是我的共享类模块:

import { HttpClient } from '@angular/common/http';

interface Project {
    demoURL: string,
    githubURL: string,
    imgFileName: string,
    name: string,
    stack: Array<string>
}

export class ProjectService {

    private configURL = `https://someURL.herokuapp.com/getAllProjects`;
    projects: any;
    constructor(private httpClient: HttpClient) {

        this.httpClient.get(this.configURL).subscribe(resp => {
            this.projects = resp;
        });
    }

    getAllProjects() {
        return this.projects;
    }
}

如你看到的,

我想projects在我的 ng 组件中使用this.service.getAllProjects(). 当我尝试记录来自共享类ProjectService的响应时,函数响应是undefined.

当我在使用初始化类之后console.log进入ProjectService构造函数时,new我可以看到我的类能够捕获响应。

为什么要这样做?另外,我该如何解决?

多谢你们。

4

3 回答 3

1

正如 user1986938 所指出的,您的问题是您的 API 调用是异步的,您必须等待 API 响应才能对您的数据执行某些操作。
Angular中,您可以依靠紧密耦合的RxJs库轻松做到这一点。Angular

这是一个工作示例,您可以轻松地适应您的情况。

您可以看到,在这个示例中我使用了 a ReplaySubject,因为它能够再次为任何新订阅者提供价值,即使在您的 API 调用完成之后也是如此。
具体来说,这允许您ProjectService多次查询所有项目的列表,并且可能从应用程序的不同部分查询,而无需多次执行真正的 API 调用,也无需关心其他任何事情。

如果你不熟悉ReactiveX概念,我建议你阅读这个很棒的文档,对于你的情况,这部分是关于Subjects.

零件

export class AppComponent
{
    // this property allows passing projects to your template
    projects: string[];

    // you can directly inject your service into your component constructor
    constructor ( private projectService: ProjectService )
    {
        // here you subscribe to you projects query observable
        this.projectService.getAll().subscribe(projects =>
        {
            // now you can do what you want with your projects
            console.log('projects: ', projects);
            // here, we store projects in component property to display them in template
            this.projects = projects;
        });
    }
}

服务

export class ProjectService
{
    // this property is used to store your API response
    private projectsSubject: ReplaySubject<any>;

    constructor ()
    {
        // create subject
        this.projectsSubject = new ReplaySubject();

        // do API call
        this.doFakeAPICall().subscribe(projects =>
        {
            // store response as subject value
            this.projectsSubject.next(projects);
        });
    }

    getAll (): Observable<any>
    {
        // return subject as observable
        return this.projectsSubject.asObservable();
    }

    // replace this be your real API call
    private doFakeAPICall (): Observable<any>
    {
        // here we simulate a response delay of one second
        return of([ 'project 1', 'project 2' ]).pipe(delay(1000));
    }
}
于 2018-09-27T08:41:28.640 回答
0

实例化 ProjectService 对象时,您无需等待响应完成。尚未设置项目属性。我建议您将 behaviorSubject 用于项目属性。您可以在此处阅读有关主题和行为主题的信息。

于 2018-09-27T07:48:25.860 回答
0

好的,所以对我有用的是在 http 请求完成时使用 EventEmitter 发出项目,如user1986938.

这就是我所做的:

服务:

import { HttpClient } from '@angular/common/http';
import { Injectable, EventEmitter } from '@angular/core';
import { Project } from '../shared/project.interface';

@Injectable()
export class ProjectService {

    private configURL = `https://someURL.herokuapp.com/getAllProjects`;
    public httpResponse = new EventEmitter<Project[]>();
    public projects: Project[];

    constructor(private httpClient: HttpClient) {
        this.httpClient.get(this.configURL).subscribe((res: Project[]) => {
            this.projects = res;
            this.httpResponse.emit(this.getProjects());
        });
    }

    getProjects() {
        return this.projects.slice();
    }
}

零件:

import { Component, OnInit } from '@angular/core';
import { ProjectService } from '../shared/project.service';
import { Project } from '../shared/project.interface';

@Component({
  selector: 'app-about',
  templateUrl: './about.component.html',
  styleUrls: ['./about.component.css'],
  providers: [ProjectService]
})

export class AboutComponent implements OnInit {

  projects: Project[];
  windowWidth: number;

  constructor(private projectService: ProjectService) { 
  }

  ngOnInit() {
    this.windowWidth = window.innerWidth;

    this.projectService.httpResponse.subscribe(([first, second]: [Project, Project]) => {
        console.log(first);
        console.log(second);
    });
  }

}
于 2018-09-29T03:50:26.533 回答