Angular Pagination: Customizing Scrolling Behavior through Scroll Event
Tags: angular, typescript
Published: 2022-04-07 12:38:27

In the previous post I made a [continuous pagination solution](https://garage.sekrab.com/posts/pagination-with-rxjs-state-and-route-params) based on route parameters. The problem we finally faced was the `scrollPositionRestoration` related issue. It is set to `enabled` as recommended, which scrolls the page up on forward navigation. The "next" click, is considered a forward navigation.

### Navigate with custom scrolling behavior
The scrolling behavior via [Scroll event](https://angular.io/api/router/Scroll) is vaguely documented in Angular [`scrollPositionRestoration`](https://angular.io/api/router/ExtraOptions):

--- Quote:

Configures if the scroll position needs to be restored when navigating back.

- `disabled` (Default) Does nothing. Scroll position is maintained on navigation.
- `top`  Sets the scroll position to x = 0, y = 0 on all navigation.
- `enabled` Restores the previous scroll position on backward navigation, else sets the position to the anchor if one is provided, or sets the scroll position to 0, 0 (forward navigation). This option will be the default in the future.

You can implement custom scroll restoration behavior by adapting the enabled behavior as in the following example.
```typescript
class AppModule {
  constructor(router: Router, viewportScroller: ViewportScroller) {
    router.events.pipe(
      filter((e: Event): e is Scroll => e instanceof Scroll)
    ).subscribe(e => {
      if (e.position) {
        // backward navigation
        viewportScroller.scrollToPosition(e.position);
      } else if (e.anchor) {
        // anchor navigation
        viewportScroller.scrollToAnchor(e.anchor);
      } else {
        // forward navigation
        viewportScroller.scrollToPosition([0, 0]);
      }
    });
  }
}
```
--- End quote.

What we want to accomplish is the same behavior except when we are paginating. First, the `scrollPositionRestoration` must be set to `disabled`.

In `app.route.ts`:
```typescript
@NgModule({
  // disable scroll position auto handling to override
  imports: [
    RouterModule.forRoot(routes, {
      scrollPositionRestoration: 'disabled',
    }),
  ],
  exports: [RouterModule],
})
export class AppRouteModule {
  // copy code from Angular
  constructor(router: Router, viewportScroller: ViewportScroller) {
    router.events.pipe(filter((event) => event instanceof Scroll)).subscribe({
      next: (e: Scroll) => {
        if (e.position) {
          // backward navigation
          viewportScroller.scrollToPosition(e.position);
        } else if (e.anchor) {
          // anchor navigation
          viewportScroller.scrollToAnchor(e.anchor);
        } else {
          // forward navigation
          // check url if page exists do not scroll
          if (!e.routerEvent.urlAfterRedirects.includes('page')) {
            viewportScroller.scrollToPosition([0, 0]);
          }
        }
      },
    });
  }
}
```
So, if the "page" exists in the url, the view port won't scroll up to 0. This actually works. Until you have a link to a page that has the term "page" in it! You probably want to be more specific in what the url contains. For my simple blog, I am happy with this solution.

Do you have other ideas? Do you do your pagination differently? Please let me know.

### Resources

- [StackBlitz App](https://stackblitz.com/edit/angular-state-local?file=src/app/app.route.ts)
- [Angular Router Extra Options](https://angular.io/api/router/ExtraOptions)