Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 65b9bbc

Browse files
committed
docs(template): add section about reverse infinite scrolling
1 parent 261d9b5 commit 65b9bbc

File tree

2 files changed

+96
-4
lines changed

2 files changed

+96
-4
lines changed

apps/docs/docs/template/api/virtual-scrolling.mdx

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,97 @@ To enable window scrolling, simply add the `scrollWindow` directive to the `rx-v
464464
</rx-virtual-scroll-viewport>
465465
```
466466

467+
## Reverse Infinite Scroll (keepScrolledIndexOnPrepend)
468+
469+
:::note Infinite Scrolling != Virtual Scrolling
470+
471+
Infinite scrolling is a scrollable pagination. Instead of loading all elements at once, they are
472+
added to the list when the user hits a certain scroll position. By default you are starting at the top and new data
473+
is _appended_ to the list, when the user hits the bottom of the list.
474+
475+
:::
476+
477+
When implementing a _reversed_ infinite scroller, you are starting from the _bottom_ of the list and _prepend_ data when
478+
users hit the top of the list. This is usually the case for chat windows like whatsapp.
479+
480+
In order to support this behavior, the virtual scroll strategies need to adjust the scrolling behavior. They should keep the
481+
currently scrolled to index stable when new data is prepended to the list.
482+
483+
You can tell the scroll strategies to do so by setting the `keepScrolledIndexOnPrepend` flag to `true`.
484+
485+
See the following example implementation.
486+
487+
<Tabs>
488+
489+
<TabItem value="component" label="Component">
490+
491+
```typescript title="reverse-infinite-list.component.ts"
492+
import { AutoSizeVirtualScrollStrategy, ListRange, RxVirtualFor, RxVirtualScrollViewportComponent } from '@rx-angular/template/experimental/virtual-scrolling';
493+
494+
@Component({
495+
imports: [RxVirtualScrollViewportComponent, RxVirtualFor, AutoSizeVirtualScrollStrategy],
496+
})
497+
export class ReverseInfiniteListComponent {
498+
initialScrollIndex = 19;
499+
500+
private dataService = inject(MessageService);
501+
// the currently rendered list range
502+
listRange: ListRange = { start: 0, end: 0 };
503+
// attach to scrollIndexChanged
504+
scrolled$ = new Subject<number>();
505+
messages$ = this.scrolled$.pipe(
506+
// only fetch when hitting the start
507+
filter(() => this.listRange.start === 0),
508+
// start with the first request
509+
startWith(0),
510+
// index will be the page we want to fetch
511+
exhaustMap((_, index) => {
512+
return this.dataService.getMessages(index);
513+
}),
514+
scan(
515+
(messages, newMessages) => [
516+
...newMessages, // <- append new messages
517+
...messages,
518+
],
519+
[],
520+
),
521+
);
522+
523+
trackMessage = (index: number, message: Message) => {
524+
return message.id;
525+
};
526+
}
527+
```
528+
529+
</TabItem>
530+
<TabItem value="template" label="Template">
531+
532+
```html title="reverse-infinite-list.component.html"
533+
<rx-virtual-scroll-viewport #viewport autosize keepScrolledIndexOnPrepend [initialScrollIndex]="initialScrollIndex" (viewRange)="listRange = $event" (scrolledIndexChange)="scrolled$.next($event)">
534+
<div
535+
*rxVirtualFor="
536+
let item of messages$;
537+
trackBy: trackMessage;
538+
renderCallback: viewsRendered$
539+
"
540+
>
541+
<div>
542+
<div>{{ item.message.text }}</div>
543+
<div>{{ item.sendAt | date }}</div>
544+
</div>
545+
</div>
546+
</rx-virtual-scroll-viewport>
547+
```
548+
549+
</TabItem>
550+
551+
</Tabs>
552+
553+
This is how the implementation looks like in real life, based on the example
554+
given in our demos application
555+
556+
<ReactPlayer playing controls url={require('@site/static/img/template/virtual-scrolling/reverse-infinite-scroll.mp4').default} />
557+
467558
## Advanced Usage
468559

469560
### Use render strategies (`strategy`)
@@ -639,10 +730,11 @@ All of them provide a twitter-like virtual-scrolling implementation, where views
639730
using css `transforms`.
640731
They also share two inputs to define the amount of views to actually render on the screen.
641732

642-
| Input | Type | description |
643-
| --------------------- | -------- | -------------------------------------------------------------------------------- |
644-
| `runwayItems` | `number` | _default: `10`_ The amount of items to render upfront in scroll direction |
645-
| `runwayItemsOpposite` | `number` | _default: `2`_ The amount of items to render upfront in reverse scroll direction |
733+
| Input | Type | description |
734+
| ---------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
735+
| `runwayItems` | `number` | _default: `10`_ The amount of items to render upfront in scroll direction |
736+
| `runwayItemsOpposite` | `number` | _default: `2`_ The amount of items to render upfront in reverse scroll direction |
737+
| `keepScrolledIndexOnPrepend` | `boolean` | _default: `false`_ If this flag is true, the virtual scroll strategy maintains the scrolled item when new data is prepended to the list. This is very useful when implementing a reversed infinite scroller, that prepends data instead of appending it |
646738

647739
See the layouting technique in action in the following video. It compares `@rx-angular/template` vs. `@angular/cdk/scrolling`
648740

Binary file not shown.

0 commit comments

Comments
 (0)