Search code examples
angularangular-routing

Goto Anchor in nested container with overflow auto


I don't can use anchor in a nestet div with overflow auto and jump to it via link. Here is the example file for my case:

https://stackblitz.com/edit/stackblitz-starters-qaldie?file=src%2Fmain.ts

(Without overflow setting in css it works)

I hope you can help me.

FULL CODE:

import { Component, Input } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import {
  InMemoryScrollingFeature,
  InMemoryScrollingOptions,
  provideRouter,
  Route,
  RouterModule,
  withComponentInputBinding,
  withInMemoryScrolling,
} from '@angular/router';
import 'zone.js';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterModule],
  template: `
    <h1>Hello from {{ name }}!</h1>

<a routerLink="./" fragment="goto"> go to anchor </a>

<div class="scroll-container">
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>
  <div>lorem ipsum</div>

  <div id="goto">lorem ipsum to goto</div>
</div>
  `,
  styles: `
  .scroll-container {
    height: 200px;
    overflow-y: auto;
  }

  #goto {
    background: red;
  }
  `,
})
export class App {
  name = 'Angular';
}

const APP_ROUTES: Route[] = [
  {
    path: '',
    redirectTo: 'sample-1',
    pathMatch: 'full',
  },
  {
    path: '**',
    redirectTo: 'sample-1',
  },
];

const scrollConfig: InMemoryScrollingOptions = {
  scrollPositionRestoration: 'top',
  anchorScrolling: 'enabled',
};

const inMemoryScrollingFeature: InMemoryScrollingFeature =
  withInMemoryScrolling(scrollConfig);

bootstrapApplication(App, {
  providers: [
    provideRouter(
      APP_ROUTES,
      withComponentInputBinding(),
      inMemoryScrollingFeature
    ),
  ],
});

Solution

  • Technically, since it's in the scroll container, it's still visible in the view port so the fragment is not working fine. If you remove the height and scroll CSS then the scroll will work fine, for this scenario, we have to use the scrollIntoView function on the view child of the element, to scroll to that element.

    Working example below.

    Full code:

    import { Component, ElementRef, Input, ViewChild } from '@angular/core';
    import { bootstrapApplication } from '@angular/platform-browser';
    import {
      InMemoryScrollingFeature,
      InMemoryScrollingOptions,
      provideRouter,
      Route,
      RouterModule,
      withComponentInputBinding,
      withInMemoryScrolling,
    } from '@angular/router';
    import 'zone.js';
    
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [RouterModule],
      template: `
        <h1>Hello from {{ name }}!</h1>
    
    <a (click)="clickEvent()" routerLink="./" > go to anchor </a>
    
    <div class="scroll-container">
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
      <div>lorem ipsum</div>
    
      <div id="goto" #goto>lorem ipsum to goto</div>
    </div>
      `,
      styles: `
      .scroll-container {
        height: 200px;
        overflow-y: auto;
      }
    
      #goto {
        background: red;
      }
      `,
    })
    export class App {
      name = 'Angular';
      @ViewChild('goto') goto!: ElementRef<any>;
    
      clickEvent() {
        if (this.goto?.nativeElement) {
          this.goto.nativeElement.scrollIntoView();
        }
      }
    }
    
    const APP_ROUTES: Route[] = [
      {
        path: '',
        redirectTo: 'sample-1',
        pathMatch: 'full',
      },
      {
        path: '**',
        redirectTo: 'sample-1',
      },
    ];
    
    const scrollConfig: InMemoryScrollingOptions = {
      scrollPositionRestoration: 'top',
      anchorScrolling: 'enabled',
    };
    
    const inMemoryScrollingFeature: InMemoryScrollingFeature =
      withInMemoryScrolling(scrollConfig);
    
    bootstrapApplication(App, {
      providers: [
        provideRouter(
          APP_ROUTES,
          withComponentInputBinding(),
          inMemoryScrollingFeature
        ),
      ],
    });
    

    Stackblitz Demo