Reputation: 2727
I have 3 private methods in the angular component which return arrays of objects.
I need to create one array of the object which will contain all 3. All of them has the same class
Here is it
export class TimelineItemDto {
id: any;
creatorAvatarUrl: string;
categoryName: string;
creatorName: string;
subcategoryName: string;
description: string;
type: string;
}
Here is the code of the component
export class HomeComponent implements OnInit {
constructor(private _router: Router, private http: HttpClient) { }
color: ThemePalette = 'primary';
classes: TimelineItemDto[] = [];
requests: TimelineItemDto[] = [];
courses: TimelineItemDto[] = [];
timelineItems: TimelineItemDto[] = [];
checked = false;
disabled = false;
ngOnInit(): void {
const token = localStorage.getItem('jwt');
if (!token) {
this._router.navigate(['/main/login']);
}
this.getTimelineItems();
}
getCourses(): any {
return this.http
.get(environment.baseUrl + '/Course/GetCourses')
.subscribe((data: TimelineItemDto[]) => {
return data;
});
}
getClasses(): any {
return this.http
.get(environment.baseUrl + '/Class/GetClasses')
.subscribe((data: TimelineItemDto[]) => {
return data;
});
}
getRequest(): any {
return this.http
.get(environment.baseUrl + '/Requests/GetRequests')
.subscribe((data: TimelineItemDto[]) => {
return data;
});
}
getTimelineItems(): any {
var courses = this.getCourses();
var classes = this.getClasses();
var requests = this.getRequest();
this.timelineItems = [...classes, ...courses, ...requests];
console.log(this.timelineItems);
}
}
At this row this.timelineItems = [...classes, ...courses, ...requests];
I have this error
core.js:4197 ERROR TypeError: classes is not iterable
How I can fix this?
Upvotes: 1
Views: 180
Reputation: 15083
Consider the code below
getCourses(): any {
return this.http
.get(environment.baseUrl + '/Course/GetCourses')
.subscribe((data: TimelineItemDto[]) => {
return data;
});
}
The above code calls .get()
method then calls .subscription()
method. This indicates that this method actually returns a subscription and NOT an Observable
. As the error indicates you are trying to iterate over these subscription hence the error
To solve this, there are various ways, my approach will be as below
Observable
Observable
Observable
Observables
to one Observable
Observable
See Below code
constructor(private _router: Router, private http: HttpClient) {}
color: ThemePalette = "primary";
timelineItems: TimelineItemDto[] = []
getCourses = () =>
this.http.get<TimelineItemDto[]>(
environment.baseUrl + "/Course/GetCourses"
);
getClasses = () =>
this.http.get<TimelineItemDto[]>(environment.baseUrl + "/Class/GetClasses");
getRequest = () =>
this.http.get<TimelineItemDto[]>(
environment.baseUrl + "/Requests/GetRequests"
);
classes$: Observable<TimelineItemDto[]> = this.getClasses();
requests$: Observable<TimelineItemDto[]> = this.getRequest();
courses$: Observable<TimelineItemDto[]> = this.getCourses();
timelineItems$: Observable<TimelineItemDto[]> = combineLatest([
this.classes$,
this.courses$,
this.requests$
]).pipe(
map(([classes, courses, requests]) => [...classes, ...courses, ...requests])
);
checked = false;
disabled = false;
ngOnInit(): void {
const token = localStorage.getItem("jwt");
if (!token) {
this._router.navigate(["/main/login"]);
}
this.getTimelineItems();
}
getTimelineItems(): any {
this.timelineItems$.subscribe({
next: (items) => this.timelineItems = items
})
}
See this solution on stackblitz
Upvotes: 2
Reputation: 31115
That isn't how asynchronous data works. Please refer here for more info on async data.
In short, you need to wait till the data is emitted by the source. In this specific case, you need to wait for the RxJS observables emit the values before trying to assign them. And seeing that you need to subscribe to multiple observables, you could use RxJS forkJoin
function to trigger the requests in parallel
export class HomeComponent implements OnInit {
constructor(private _router: Router, private http: HttpClient) { }
color: ThemePalette = 'primary';
classes: TimelineItemDto[] = [];
requests: TimelineItemDto[] = [];
courses: TimelineItemDto[] = [];
timelineItems: TimelineItemDto[] = [];
checked = false;
disabled = false;
ngOnInit(): void {
const token = localStorage.getItem('jwt');
if (!token) {
this._router.navigate(['/main/login']);
}
this.getTimelineItems();
}
getTimelineItems(): any {
forkJoin(
<Observable<TimelineItemDto[]>>this.http.get(environment.baseUrl + '/Class/GetClasses'),
<Observable<TimelineItemDto[]>>this.http.get(environment.baseUrl + '/Course/GetCourses'),
<Observable<TimelineItemDto[]>>this.http.get(environment.baseUrl + '/Requests/GetRequests')
).subscribe({
next: ([classes, courses, requests]) => {
this.classes = classes;
this.courses = courses;
this.requests = requests;
this.timelineItems = [...classes, ...courses, ...requests];
console.log(this.timelineItems);
},
error: error => {
console.log('handle error');
}
});
}
}
Please go through the link above. The variable this.timelineItems
might still be empty when you try to access it outside the subscription as it might not yet be assigned the values.
In other words, the this.timelineItems
would only be properly accessible inside the subscription.
Upvotes: 1