如何在共享 class 和 angular 2 组件之间传输数据?

How do I transfer data between a shared class and an angular 2 component?

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

这是我的组件:

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;
  }

}

这是我共享的 class 模块:

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;
    }
}

如您所见,

我想使用 this.service.getAllProjects() 在我的 ng 组件中填充我的局部变量 projects。当我尝试记录来自共享 class ProjectService 的响应时,函数响应是 undefined.

当我在 ProjectService 构造函数中 console.log 使用 new 初始化 class 后,我可以看到我的 class 能够捕获响应.

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

谢谢大家。

您在实例化 ProjectService 对象时没有等待响应完成。项目 属性 尚未设置。我建议您对项目 属性 使用 behaviorSubject。您可以阅读有关 subjects 和 behaviorSubject here 的内容。

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

这是一个working example,您可以轻松地适应您的情况。

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

如果您不熟悉 ReactiveX 概念,我建议您阅读这篇关于 Subjects.

的精彩 documentation, and for your case, this part

组件

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));
    }
}

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

这是我所做的:

HttpService:

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);
    });
  }

}