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!