rintoj / ngx-virtual-scroller

Virtual Scroll displays a virtual, "infinite" list.
https://rintoj.github.io/ngx-virtual-scroller
MIT License
979 stars 295 forks source link

vsStart keeps firing even after data prepended to the list #473

Open pfalcon64 opened 4 years ago

pfalcon64 commented 4 years ago

I'm trying to dynamically (lazy) load data from a very large list, but also allowing the user to "remember" the position they were last in. Which means that I may need to unshift data to the top of the list when the user scrolls upwards.

Adding to the bottom isn't a problem - vsEnd fires, you push() data to the buffer, its happy. User scrolls down a bit more and the process repeats itself. Loading from position 0 in my list is easy, and works well.

But vsStart doesn't behave itself. Its called when startIndex = 0. I prepend data to the buffer (above startIndex), but the event keeps firing infinitely (the display never catches up). The demo program does this - click the prepend option without doing anything else, and it will get stuck in an infinite loop - constantly adding data - but you only notice this by the "flash", as it also keeps highlighting the (new) top row, instead of showing you visually that you just inserted data ABOVE that position...? This is the example you can work with to correct the problem.

In my screen I added test code to stop this after one iteration, and I find that the virtual scroller has confused itself between the relative position of startIndex at the beginning of the vsStart event, and what that buffer position is by definition at the end. At the end of the event, the original startIndex is now offset 21 in the (new) list, but it doesn't seem to recognise this automatically. I can't change these values myself, and even if I attempt a scrollToIndex, the event fires several times before that takes effect.

I had expected this to work like the vsEnd event, where if you add to the buffer before the current position, then the UI doesn't register anything except the scroll bar position adjusting downwards slightly. The event would only fire once, as it would recognise that its relative position in the list is no longer at the top, and would only fire again when the users scrolls up again.

metzzo commented 3 years ago

If someone else stumbles upon this issue, I solved this problem by manually scrolling the list to the "old" position. Something similar like this:

this.scroller.scrollToIndex(this.list.length - oldLength, true, 0, 0);

where this.list is the length of the list after prepending data and oldLength is the length of the list before prepending. This workaround seems to solve the issue for me.