Angular 6 HttpClient назначает результирующую полезную нагрузку массиву - PullRequest
0 голосов
/ 01 сентября 2018

Я пытаюсь выполнить вызов get в angular, сам вызов работает, так как я могу поместить журнал в подписку и посмотреть возвращенные данные, проблема, с которой я сталкиваюсь, это то, что я не могу назначить данные для моего существующего массива (В настоящее время пусто) и, как показано ниже, код имеет тип Event[]. Я попытался использовать карту для массива данных, который также имеет тип Event[], но безуспешно и то же самое с push, хотя я считаю, что это потому, что вы не можете выдвинуть массив. Я уверен, что есть кое-что простое, что я пропускаю или не могу найти.

Вот звонок, который я делаю, и ниже, что модель 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, поэтому могу ошибаться, любая помощь очень ценится.

EDIT

У меня есть еще несколько исследований, но все еще нет радости, может быть, это связано с подпиской. Я попробовал некоторые решения клонирования массива отсюда

РЕДАКТИРОВАТЬ 2

Глядя дальше, я вижу, что содержимое подписки - это функция, то есть что-то, чего мне не хватает в области действия, требует ли моя this.events какой-то передачи, она установлена ​​на уровне класса.

РЕДАКТИРОВАТЬ 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();

Ответы [ 3 ]

0 голосов
/ 01 сентября 2018

Из рассмотрения вашего третьего редактирования я думаю, что проблемы map/pipe - это «красная сельдь», а основная проблема заключается в реализации асинхронного вызова http внутри сигнатуры открытого метода, который ведет себя синхронно, то есть getEvents() .

Например, я ожидал бы, что этот фрагмент кода будет вести себя аналогично, поскольку метод может немедленно вернуть 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);
    }
}
0 голосов
/ 02 сентября 2018

Есть несколько проблем с вашим кодом.

Согласно вашему коду, вы не можете понять Обозримый RxJS. Вы звоните подписаться, когда вы наконец готовы слушать. Таким образом, ваш getEvents() метод не должен подписываться, а должен возвращать наблюдаемое. т.е.

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 делает subscribe для вас в html. Просто выставьте events$, как вы уже сделали в ngOnInit().

Я бы не определил свой интерфейс как Event, потому что Event уже является частью RxJS .

Кроме того, поскольку вы вызываете свой console.log вне подписки, он всегда будет нулевым, если вы не добавите tap из RxJS , как это.

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

Кроме того, почему вы звоните как Http и HttpClient. Или используйте клиент или http.

Счастливое кодирование

0 голосов
/ 01 сентября 2018

Основная проблема в том, что вы пытаетесь вернуть данные Event[] из вашего метода AdminService.getEvents() до httpClient.get<Event[]>() разрешения / излучения и subscribe() выполнения / назначения, поэтому он всегда возвращает пустой массив. Это просто асинхронная природа 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;
}

Вместо этого верните 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 с типом не будет автоматически создавать экземпляры класса Event из типизированного get(), это объекты с установленным типом. Вы можете использовать оператор RxJS map в сочетании с Array.prototype.map, чтобы создать экземпляр класса Event для каждого типизированного объекта Event, возвращаемого из get<Event[]>. Также будьте осторожны с именами Event, так как они могут конфликтовать с существующим символом Событие .

Надеюсь, это поможет!

...