1

After a couple of days of research and experiments, I can't seem to be able to replicate the following typical Instagram behavior in Angular 8, using Angular Material's cdk-virtual-scroll-viewport.

  1. Click on an image from the profile's grid of images
  2. Open an infinite scroll of images, centered on the clicked image, while having the previous and next images loaded below and above it.

The problem specifically lies on opening the virtual scroll centered on the clicked image.


My setup:

  1. the Profile Component loads the image grid with an *ngFor="let post of posts"
  2. On click, a new Timeline Component is initiated, receiving the above posts array as a state with [state]='{ data: posts }', along with the clicked post's array position.
  3. Everything works, the feed (timeline, as I call it) is loaded, but although I can make it scroll to the clicked post position with this.viewPort.scrollToIndex(index), I can't make it load on this position directly.

Why don't I want it to simply scroll there although it is almost instant? Because all the HD images that precede the clicked post will be pulled from the server in order to be loaded as the feed scrolls it's way there. Imagine if the clicked post has 20 other image posts before it.

What else have i tried:

I've tried cutting the posts array right before the clicked post, loading that second part of the array (which starts with he clicked post) with a *cdkVirtualFor="let post of posts", and then pushing the first part of the array in the beginning of posts so that it will load above the fold. But, when the first part of the array is prepended in posts, the view navigates to the top of the page (first post) instead of loading the prepended posts above the fold, which is what I want.

Any ideas on how to make this sorcery work will be highly appreciated.

Konstantinos T.
  • 415
  • 5
  • 11

1 Answers1

0

I still haven't found a way to start rendering from the clicked post, but the best workaround I found was the following.

It turns out that using this.viewPort.scrollToIndex(scrollIndex, "auto") - pay attention to the auto parameter - does not actually scroll through the page but practically teleports directly to the desired index. Which means that, if you call the method soon enough, no other items between the beginning of the page and the index you land on will be loaded from the server. You can check this experiment in this StackBlitz with the Network tab on chrome dev tools open.

Now, trying to run the above command the way it was intended, like so:

  ngAfterViewInit() {
    this.viewPort.scrollToIndex(i);
  }

you will probably figure out that it doesn't work. Two solutions to this bug has been offered here. They both work, but calling setTimeout() is visibly slower as you actually see the "snap" to the new index when the page loads. Thus, the best way to handle this is to run the scrollToIndex() method in an ngAfterViewChecked() hook instead of an ngAfterViewInit(), like so:

  ngAfterViewChecked() {
    this.viewPort.scrollToIndex(i);
  }

It is not a perfect solution but it does practically replicate the desired experience to the end user.

Konstantinos T.
  • 415
  • 5
  • 11