Angular 6 HttpClient 将生成的负载分配给数组

Angular 6 HttpClient assign resulting payload to array

我正在尝试在 angular 中调用 get 调用本身有效,因为我可以在订阅中输入日志并查看返回的数据我遇到的问题是我似乎无法分配数据到我现有的数组(当前为空),因为下面的代码是 Event[] 类型。我曾尝试在数据数组上使用映射,该映射也是 Event[] 类型,但没有运气,与推送相同,尽管我相信这是因为您无法推送数组。我确定我缺少或找不到一些简单的东西。

这是我正在进行的调用,下面是事件模型。

this.httpClient.get<Event[]>('http://127.0.0.1:5555/events-get').subscribe((data) => this.events = data); 


export class Event {
    constructor(public name: String, public date: Date, public time: Date) {}
}

我是 angular 的新手,所以我可能做错了,非常感谢任何帮助。

编辑

我做了更多的研究,但仍然不高兴,也许这与订阅有关。

编辑 2

进一步看,我看到订阅的内容是一个函数,我的 this.events 是否需要以某种方式传递,它设置在 class 级别。

编辑 3

import { Event } from '../shared/event.model';
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Subject } from 'rxjs';
import { map } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http'

@Injectable()
export class AdminService {
    eventsChanged = new Subject<Event[]>();

    private events: Event[] = [];

    constructor(private http: Http, private httpClient: HttpClient) {}

    getEvents() {
        this.httpClient.get<Event[]>('http://127.0.0.1:5555/events-get')
        .pipe(
            map(
                (data: Event[]) => data.map(event => {
                // may need to coerce string to Date types
                    return new Event(event.name, event.date, event.time)
                })
            )
        )
        .subscribe((events: Event[]) => this.events = events);

        console.log(this.events);
        return this.events;
}

然后我在我的组件中使用这个调用,这与使用 Event[].

的本地数组工作时相比并没有改变
 this.events = this.adminService.getEvents();

基本问题是您试图在 httpClient.get<Event[]>() resolving/emitting 和 [=19= 之前 return 来自 AdminService.getEvents() 方法的 Event[] 数据] executing/assigning,这就是为什么它总是 returning 一个空数组。这就是 HttpClient 和 RxJS 的异步特性。

@Injectable()
export class AdminService {
// ...

getEvents() {
    // this happens after console.log() and return this.events
    .subscribe((events: Event[]) => this.events = events);

    // this executes before get()/subscribe() resolves, so empty [] is returned
    console.log(this.events);
    return this.events;
}

代替return get<Event[]>().pipe()代替@Component调用和利用:

import { Event } from '../shared/event.model';
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Subject, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http'

@Injectable()
export class AdminService {
  eventsChanged = new Subject<Event[]>();

  constructor(private http: Http, private httpClient: HttpClient) {}

  getEvents(): Observable<Event[]> {
    return this.httpClient.get<Event[]>('http://127.0.0.1:5555/events-get')
      .pipe(
        map(
          (data: Event[]) => data.map(event => {
            // may need to coerce string to Date types
            return new Event(event.name, event.date, event.time)
           })
        )
      );
  }

组件:

@Component({ /* ... */ })
export class EventsComponent implements OnInit {
  events$: Observable<Event[]>;

  constructor(private adminService: AdminService) {}

  ngOnInit() {
    this.events$ = this.adminService.getEvents();
  }
}

带有异步管道的模板:

<ul>
  <li *ngFor="let event of events$ | async">{{event.name}}</li>
</ul>

或者:

@Component({})
export class EventsComponent implements OnInit {
  events: Event[] = [];

  constructor(private adminService: AdminService) {}

  ngOnInit() {
    this.adminService.getEvents()
      .subscribe(events => this.events = events);
  }
}

模板:

<ul>
  <li *ngFor="let event of events">{{event.name}}</li>
</ul>

附带说明,具有类型的 HttpClient 不会自动从类型化的 get() 创建 Event class 的实例,它是具有集合类型的对象.您可以结合使用 RxJS map 运算符和 Array.prototype.map 为每个 Event 类型的对象 return 创建一个 class Event 实例=30=]。还要小心将其命名为 Event,因为它可能与现有符号 Event.

冲突

希望对您有所帮助!

通过查看您的第三次编辑,我认为 map/pipe 问题是转移注意力的问题,核心问题是在 public 方法中实现异步 http 调用同步行为的签名,即 getEvents().

例如,我希望这个 code snippet 的行为类似,因为该方法能够立即 return this.events,其值仍然是一个空数组,然后继续在异步 setTimeout

中执行指定的行为
private events: Event[] = [];
private event1: Event = new Event("event1", "date", "time");
private event2: Event = new Event("event2", "date", "time");
public getEvents(): Event[] {
   setTimeout(() => {
     this.events = [..., event1, event2];
   }, 5000);

   return this.events;
}

对于您的代码示例,您是否能够通过与此类似的代码实现获得所需的结果。 StackBlitz 上可用的完整功能实现:

export class AdminService {
...
   public getEvents(): Observable<Event[]> {
   // Returns an observable
   return this.httpClient.get<Event[]>(url);
  }
}

export class EventComponent {

constructor(private adminService: AdminService) {}
    public events: Event[] = [];

    ngOnInit() {
        // Subscribe to the observable and when the asynchronous method
        // completes, assign the results to the component property.
        this.adminService.getEvents().subscribe(res => this.events = res);
    }
}

您的代码存在多个问题。

As per your code, you are unable to understand the RxJS Observable. You call subscribe, when you are finally ready to listen. So your getEvents() method should not subscribe, rather return the observable. i.e.

getEvents(): Observable<Event[]> {
  return this.httpClient
    .get<Event[]>("http://127.0.0.1:5555/events-get")
    .pipe(
      map(data =>
        data.map(event => new Event(event.name, event.date, event.time))
      )
    );
}

自您使用以来

<ul>
  <li *ngFor="let event of events$ | async">{{event.name}}</li>
</ul>

async 管道在 html 中为您完成 subscribe。就像您在 ngOnInit() 中所做的那样公开 events$

I wouldn't define my interface as Event because Event is already part of RxJS.

此外,由于您在订阅之外调用 console.log,它将始终为空,除非您像这样从 RxJS 添加 tap .

import { Event } from "../shared/event.model";
import { Injectable } from "@angular/core";
import { Http, Response } from "@angular/http";
import { Subject } from "rxjs";
import { map, tap } from "rxjs/operators";
import { HttpClient } from "@angular/common/http";

@Injectable()
export class AdminService {
  constructor(private http: Http, private httpClient: HttpClient) {}

  getEvents(): Observable<Event[]> {
    return this.httpClient
      .get<Event[]>("http://127.0.0.1:5555/events-get")
      .pipe(
        map(data =>
          data.map(event => new Event(event.name, event.date, event.time))
        ),
        tap(console.log)
      );
  }
}

Also, why are you calling both Http and HttpClient. Either use the client or http.

快乐编码