Currently, I am still a beginner in Angular and learning Angular 8.
I am in the process of creating a simple API communication service to retrieve the necessary data for display. Within my main component, there is a sub-component that also needs to fetch data for loading.
Though I have followed various tutorials, I keep encountering a recurring issue where the component loads before the API HTTP request completes, resulting in undefined data.
My current API service utilizes HttpClient
for communication with the API:
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators;
@Injectable({
providedIn: 'root'
})
export class ApiService {
constructor(private http: HttpClient) {}
getUserFeed(id: number): Observable<Post[]> {
return this.http
.get<Post[]>(`${API_URL}/feed`)
.pipe(
retry(3),
catchError(this.handleError)
);
}
getProfile(id: number): Observable<Profile> {
return this.http
.get<Profile>(`${API_URL}/profile/${id}`)
.pipe(
retry(3),
catchError(this.handleError)
);
}
handleError(error: any) {
let errorMessage: string;
// Set error message
(error.error instanceof ErrorEvent) ?
errorMessage = error.error.message :
errorMessage = `Error Code: ${error.code}\nMessage: ${error.message}`;
console.log(errorMessage);
return throwError(errorMessage);
}
}
The expected response from the API should be an array of Posts
.
In my component, I make use of this service as follows:
import { Component, OnInit } from '@angular/core';
import { UserService } from '../user/user.service';
import { ApiService } from '../api/api.service';
import { User } from '../user';
import { Post } from '../Post';
@Component({
selector: 'app-feed',
templateUrl: './feed.component.html',
styleUrls: ['./feed.component.css'],
})
export class FeedComponent implements OnInit {
posts: Post[] = [];
user: User;
post: Post;
constructor(private userService: UserService) {
this.user = this.userService.user;
}
public ngOnInit() {
this.userService.getUserFeed(this.user.id).subscribe((feed) => {
this.posts = feed;
console.log(this.posts);
});
}
}
The HTML template of my component loops through these posts and passes them to the sub-components:
<div *ngIf="posts.length">
<mat-list *ngFor="let post of posts">
<!-- Post Display -->
<app-post-display [post]=post></app-post-display>
<!-- Post Interaction Row -->
<app-post-interaction-bar [post]=post></app-post-interaction-bar>
<!-- Comment Preview -->
<app-comment-preview [post]=post></app-comment-preview>
<mat-divider></mat-divider>
</mat-list>
</div>
While everything seems fine with displaying posts in the main component, I encounter an issue within the sub-component app-post-display
, which retrieves the author information from the post.authorId
property.
I have initialized the author variable and placed the logic to fetch author data in the ngOnInit function, but unfortunately, I consistently receive
ERROR TypeError: Cannot read property 'id' of undefined
in the console. It appears that the component attempts to display before fetching the author data.
What adjustments do I need to make to ensure the author data is fetched prior to loading the component display?
import { Component, Input, OnInit } from '@angular/core';
import { UserService } from '../user/user.service';
import { User } from '../user';
import { Post } from '../post';
import { Profile } from '../profile';
import { ApiService } from '../api/api.service';
@Component({
selector: 'app-post-display',
templateUrl: './post-display.component.html',
styleUrls: ['./post-display.component.css'],
})
export class PostDisplayComponent implements OnInit {
@Input() post: Post;
user: User;
author: Profile;
constructor(private userService: UserService, private backend: BackendService) {
this.user = this.userService.user;
}
ngOnInit() {
this.backend.getProfile(this.post.authorId).subscribe((profile) => {
this.author = profile;
console.log(this.author);
});
}
}