Angular 6 HttpClient assign resulting payload to array

send array in post request angular 6
angular httpclient post
angular 2 http get example
angular http get with body
angular/common/http
httpoptions angular
angular 6 http post example with parameters
angular-httpclient set headers

I am attempting to do a get call in angular the call itself works as I can put a log in the subscribe and see the returned data the issue I am having is I can't seem to assign the data to my existing array (Currently Empty) and as the code below is of type Event[]. I have tried using a map on the data array which is also of type Event[] but no luck and the same with push although I believe this is because you can't push an array. I am sure there is something simple I am missing or can't find.

Here is the call I am making and bellow that the Event model.

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

I am new to angular so I could be doing it all wrong any help is much appreciated.

EDIT

I have dome some more research but still no joy maybe this is something to do with having it in subscribe. I tried some of the array clone solutions from here

EDIT 2

Looking further I see that the contents of subscribe are a function is there something I am missing with scope does my this.events need passing in some way, it's set at the class level.

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

I am then using this call in my component this hasn't changed from when it worked using a local array of Event[].

 this.events = this.adminService.getEvents();

The base issue is you are attempting to return the Event[] data from your AdminService.getEvents() method prior to httpClient.get<Event[]>() resolving/emitting and subscribe() executing/assigning, that is why it is always returning an empty array. This is simply the asynchronous nature of HttpClient and 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;
}

Instead return the get<Event[]>().pipe() instead for the @Component to call and utilize:

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:

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

  constructor(private adminService: AdminService) {}

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

Template with async pipe:

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

Or:

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

  constructor(private adminService: AdminService) {}

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

Template:

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

On a side note, HttpClient with a type will not automatically create instances of Event class from a typed get(), it is objects with a set type. You could use the RxJS map operator in combination with Array.prototype.map to create an instance of class Event for each Event typed object return from get<Event[]>. Also be careful with naming it Event as it could conflict with an existing symbol Event.

Hopefully that helps!

Communicating with backend services using HTTP, The HttpClient in @angular/common/http offers a simplified client HTTP API Re​-subscribing to the result of an HttpClient method call has the effect of reissuing the HTTP request. Then import and add it to the AppModule providers array like this: Typescript disallows the following assignment because req.url is readonly  Trying to send a multidimensional array to an API but angular http.get doesn't let me, this is total rubbish, time after time I get baffled how such simple things are so complicated or not possible at all with angular 2+, totally regretting not picking up something else like react.

There are multiple problems with your code.

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

Since you have used

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

The async pipe does the subscribe for you in the html. Just expose the events$ like you have already done in the ngOnInit().

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

Also, since you are calling your console.log outside the subscription, it will always be null, unless you add a tap from RxJS like this.

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.

Happy Coding

Angular HTTP Client - QuickStart Guide, This post will be a quick practical guide for the Angular HTTP Client module. How to do HTTP Requests in sequence, and use the result of the first As we can see this data is a JSON structure, with no arrays. Instead, a call to set will return a new HttpParams object containing the new value properties. Note: Angular 6 deprecated the old http client in favor of the newer http client module which is an improved version of the http client API that lives in the @angular/common/http package. The old API is still available in @angular/http in Angular 6, but is now removed in Angular 9.

From reviewing your third edit, I think the map/pipe issues are a red-herring and the core issue is the implementation of an asynchronous http call inside of a public method signature that behaves synchronously, i.e., getEvents().

For example, I would expect this code snippet to behave similarly, in that the method is able to immediately return this.events, whose value is still an empty array, and then proceed with executing the specified behavior inside of the asynchronous 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;
}

For your code example, are you able to get the desired results with a code implementation similar to this. Complete functional implementation available on 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);
    }
}

HttpParams doesn't accept array · Issue #19071 · angular/angular , closca opened this issue on Sep 6, 2017 · 22 comments. Open let payload = new HttpParams(); payload.set('ids', [1,2,3,4]); feat(common): accept numeric value for HttpClient params #19595 new HttpParams({ fromObject: object, }); Previous result before PR: key=foo&key=bar New result after PR: key[]=foo&key​[]=bar. As of Angular 5.0, the older Http service still works, but it's deprecated and has been removed in Angular 6.0. The code samples in this post are compatible with Angular 4.3 and 5.x (and 6.x with rxjs-compat). If your project is still using Angular 4.2 or lower, including Angular 2, see my previous posts on making API calls with the Http service.

Consuming APIs in Angular: The Model-Adapter Pattern, A TypeScript-friendly pattern to improve how you integrate Angular apps and REST APIs. the resulting Object in our Angular components and HTML templates. As it turns out, Angular's HttpClient can do just this for you, so we wouldn't even have to We'll map the data array to an array of Course objects:. For this purpose, Angular provides the HttpClient service. HTTP client in Angular - Getting Started Import HttpClientModule. To use any service, you need to import the respective module. For HttpClient you can get started by importing the HttpClientModule. You may import it into any Angular module utilizing the HttpClient.

Observables Array Operations, Here we have used it to create a new result set by excluding any user whose id property is less than six. Now when our subscribe callback gets invoked, the data it  That command will create a new Angular 8 app with the name `angular-httpclient` and pass all questions as default then the Angular CLI will automatically install the required NPM modules. After finished, go to the newly created Angular 8 folder then run the Angular 8 app for the first time.

Angular 2: Using the HTTP Service to Write Data to an API, You can find a tutorial for the HttpClient service in my post Angular 5: The entire operation will result in an error state if any single request fails  Important: the In-memory Web API module has nothing to do with HTTP in Angular. If you're just reading this tutorial to learn about HttpClient, you can skip over this step. . If you're coding along with this tutorial, stay here and add the In-memory Web API n

Comments
  • I see there are three votes to close, did I not give enough information? If not what do you need?
  • In your original example, if you instead log inside the subscribe(), are you seeing the data you expect? subscribe((data) => console.log(data));
  • Yes I see the json posted from the server it's just not saving to the other array and both are shown as type Event[]
  • Can you clarify the intent/need for the multiple rxjs operators? I'm familiar with seeing the map operator in code that imports and uses the HttpModule, but one of the advantages of the HttpClientModule is that it handles type-checking and serialization for you. The example StackBlitz I provide in my solution below removes the rxjs operators and is still able to correctly handle serialization to the specified type.
  • I don't know I am only half way through the angular course and the instructor likes to show you multiple implementations then change them later showing you how to do it badly then how it should be done.
  • Sorry but same issue this.events is still empty
  • When/where exactly are you trying to use this.events, if you are attempting to log it prior resolving it will be undefined.
  • it's not undefined it's empty I define it at the top shown as [] the get runs in a function that returns this.events
  • You please would need to show how you are using this.events and calling the get() in your component exactly. You are absolutely sure you are getting data from the server? There must be something else going on.
  • @bobthemac I've updated the answer, you simply cannot return this.events from the service like that as it resolves before subscribe() executes. Instead return the Observable<Event[]> instead and execute the subscribe in the @Component. Thanks!
  • I am part way through an angular course, haven't got to observables yet. I haven't used async in the template, and haven't gotten to the upgrade everything to httpclient part either. Thanks for the answer though some good point in their all taken onboard.