Sekrab Garage

Angular Router Extra Options

Angular Pagination: Customizing Scrolling Behavior through Scroll Event

TipAngular April 7, 22
Subscribe to Sekrab Parts newsletter.

In the previous post I made a continuous pagination solution based on route parameters. The problem we finally faced was the scrollPositionRestoration related issue. It is set to enabled as recommeneded, which scrolls the page up on forward navigation. The "next" click, is considered a forward navigation.

anchorNavigate with custom scrolling behavior

The scrolling behavior via Scroll event is vaguely documented in Angular scrollPositionRestoration:

--- 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.

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:


@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.