0

I'm trying to implement ngx-infinite-scroll. I want to take the first 5 posts out of my "posts" array and put them into "shownPosts" array at the start and then when the user keeps scrolling down I want it to add another 5 but I ran into a problem where my "posts" array is empty while the side is still loading (ngOnInit).

If I check the array with another function (checkPosts) later it's got all of the Posts. Why is that?

Console logs when website loads:

In constructor, this.posts.length: 0
In ngOnInit, this.posts.length: 0
ERROR TypeError: Cannot read properties of undefined (reading 'title')       core.mjs:6485 
    at HotComponent.ngOnInit (hot.component.ts:37:70)
    at callHook (core.mjs:2542:1)
    at callHooks (core.mjs:2511:1)
    at executeInitAndCheckHooks (core.mjs:2462:1)
    at refreshView (core.mjs:9499:1)
    at refreshComponent (core.mjs:10655:1)
    at refreshChildComponents (core.mjs:9280:1)
    at refreshView (core.mjs:9534:1)
    at refreshEmbeddedViews (core.mjs:10609:1)
    at refreshView (core.mjs:9508:1)

Console log after I run "checkPosts()" through a button once the site has loaded:

In checkPosts, this.posts.length: 32
In checkPosts, this.posts[0].title: This is the first posts title.

hot.component.ts:

import ...

@Component({
...
})

export class HotComponent implements OnInit {
  posts: Post[] = [];
  shownPosts: Post[] = [];
  normalDrawerShown: boolean = true;
  subscription!: Subscription;
...

constructor(private postService: PostService, private uiService: UiService) {
  this.subscription = this.uiService
  .onToggleNormalDrawer()
  .subscribe((value) => (this.normalDrawerShown = value));

  console.log("In constructor, this.posts.length: "+ this.posts.length);
}

ngOnInit(): void {
  this.postService.getPosts().subscribe((posts) => (this.posts = posts));

  console.log("In ngOnInit, this.posts.length: "+ this.posts.length);
  console.log("In ngOnInit, this.posts[0].title: " + this.posts[0].title);
}

checkPosts():void{
  console.log("In checkPosts, this.posts.length: "+ this.posts.length);
  console.log("In checkPosts, this.posts[0].title: " + this.posts[0].title);
}
...
}

Post.ts:

export interface Post {
  id?: number;
  title: string;
  fileName: string;
  url: string;
  section: string;
  postTime: string;
  upvotes: number;
  downvotes: number;
  comments: number;
}

post.service.ts:

getPosts():Observable<Post[]> {
  return this.http.get<Post[]>(this.apiUrl);
}
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Critix
  • 3
  • 1
  • Yes, that's how async processes work. You need to deal with the fact that you don't have the value to start with - provide a default value, guard against early access, use the async pipe, ... – jonrsharpe Feb 20 '22 at 18:00

1 Answers1

0

Http request to backend api take time.

this line of code:

this.postService.getPosts().subscribe((posts) => (this.posts = posts));

...means that when observable created here:

this.http.get<Post[]>(this.apiUrl);

...emits value (therefore when http request return some value) then take that value and assign it to this.posts. And since http requests take some time, that value is not showed when you try to console.log it right after subscription.