angulartypescriptscrollangular2-routing

Angular: Scroll to a section on page load when navigating to a specific URL fragment


I'm working on an Angular application and I have a function that scrolls smoothly to a specific section on the page. The function works perfectly when I trigger it manually. However, I want the page to automatically scroll to a specific section when the user navigates directly to a URL with a fragment, such as http://localhost:4200/section-2.

How can I modify my code or implement additional logic to make sure that when the page is loaded with a specific fragment in the URL, it automatically scrolls to that section?

Here's my current scroll function:

public scrollToSection(sectionId: string): void {
  const targetElement = document.getElementById(sectionId);
  if (targetElement) {
    const navHeight = this.navigationService.getNavHeight();
    const yPosition = targetElement.getBoundingClientRect().top + window.scrollY - navHeight;
    window.scrollTo({ top: yPosition, behavior: 'smooth' });
  }
}

Solution

    1. You should have a component to wrap all the sections. In this component, extract the first route path and scroll to the section.

    home.component.ts

    import { Component } from '@angular/core';
    import { Section1Component } from '../section1/section1.component';
    import { Section2Component } from '../section2/section2.component';
    import { Section3Component } from '../section3/section3.component';
    import { Section4Component } from '../section4/section4.component';
    import { CommonModule } from '@angular/common';
    import { ActivatedRoute } from '@angular/router';
    import { NavigationService } from '../navigation.service';
    
    @Component({
      selector: 'app-home',
      standalone: true,
      imports: [
        Section1Component,
        Section2Component,
        Section3Component,
        Section4Component,
        CommonModule,
      ],
      template: `
        <app-section1></app-section1>
        <app-section2></app-section2>
        <app-section3></app-section3>
        <app-section4></app-section4>
      `,
    })
    export class HomeComponent {
      name = 'Angular';
    
      constructor(
        private activatedRoute: ActivatedRoute,
        private navigationService: NavigationService
      ) {}
    
      ngOnInit(): void {
        this.activatedRoute.pathFromRoot &&
          this.activatedRoute.pathFromRoot.length > 0 &&
          this.activatedRoute.pathFromRoot[1].url.subscribe((url) => {
            let elementId = url[0].path;
    
            this.scrollToSection(elementId);
          });
      }
    
      public scrollToSection(sectionId: string): void {
        const targetElement = document.getElementById(sectionId);
        if (targetElement) {
          const navHeight = this.navigationService.getNavHeight();
          const yPosition =
            targetElement.getBoundingClientRect().top + window.scrollY - navHeight;
          window.scrollTo({ top: yPosition, behavior: 'smooth' });
        }
      }
    }
    
    1. In your routes, point all the section URLs to the HomeComponent.

    app.route.ts

    import { HomeComponent } from './home/home.component';
    
    export const routes: Routes = [
      { path: 'section-1', component: HomeComponent },
      { path: 'section-2', component: HomeComponent },
      { path: 'section-3', component: HomeComponent },
      { path: 'section-4', component: HomeComponent },
      { path: '**', redirectTo: '' },
    ];
    
    1. Provide the routes in the provideRouter function.

    main.ts

    import { routes } from './app/app.routes';
    
    bootstrapApplication(App, {
      providers: [provideAnimations(), provideRouter(routes)],
    }).catch((err) => console.error(err));
    
    1. Currently, you do not utilize the route and render the component. You have to apply the <router-outlet> in the template in the main.ts. Remove the imports of the section components from the App.

    main.ts

    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [
        NavComponent,
        CommonModule,
        RouterModule,
      ],
      template: `
      <div class="container">
         <app-nav></app-nav> 
         <router-outlet></router-outlet>
      </div>
      `,
    })
    

    Demo @ StackBlitz