How can I navigate to an anchor in Angular 7
Asked Answered
B

2

9

I've enable the anchorScrolling in routingModule and all the path but when i click on links nothing happened.

'nav-bar.component.html'

<div id="mySidenav" class="sidenav" #sidenav>
   <a href="javascript:void(0)" class="closeBtn" 
   (click)="closeNav()">&times;</a>
   <a routerLink="/hazyMinds" [fragment]="'HazyMinds'">HazyMinds</a>
   <a routerLink="/ourGames" [fragment]="'Games'">Our Games</a>
   <a routerLink="/contact" [fragment]="'Contact'">Contact</a>
</div>
<span id="openNavBtn"  (click)="openNav()" #openBtn>&#9776;</span>



'app.component.html'

<app-nav-bar></app-nav-bar>
<app-hazy-minds id="HazyMinds"></app-hazy-minds>
<app-games id="Games" ></app-games>
<app-contact id="Contact"></app-contact>
<router-outlet></router-outlet>



'app-routing.module.ts'

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';

import {ContactComponent} from './contact/contact.component';
import {GamesComponent} from './games/games.component';
import {HazyMindsComponent} from './hazy-minds/hazy-minds.component';

const routes: Routes = [
  {path: '', redirectTo: '/', pathMatch: 'full'},
  {path: 'hazyMinds', component : HazyMindsComponent},
  {path: 'ourGames', component : GamesComponent},
  {path: 'contact', component : ContactComponent}
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes, {
      scrollPositionRestoration: 'enabled',
      anchorScrolling: 'enabled',
      scrollOffset: [0, 64]
    }),
    CommonModule
  ],
  exports: [
    RouterModule
  ]
})


export class AppRoutingModule { }

I expect that when i clicked on link it automatically scroll to the correct anchor.
Someone know what's wrong with my code? thanks

Barbuto answered 19/12, 2018 at 16:16 Comment(0)
S
10

You can use fragments for this:

this.router.navigate(['/results'], { fragment: 'top' });

//

<h1 id="top">asdasd</h1>

https://angular.io/api/router/NavigationExtras

Selfassurance answered 19/12, 2018 at 16:22 Comment(1)
it should be <h1 id="top"> not fragmentGethsemane
A
7

For me, other solutions worked OK for initial navigation but no matter what I tried, I could not get the anchor scrolling to work with navigation history.

In other words, when I went "back" or "forward" in my browser, the URL would update but I could not get Angular to scroll to the proper place. From logging, it seems that Angular was not actually acknowledging the fragment when going back/forward and so the scrolling was not being triggered.

I decided to subscribe to the URL and manually scroll when a fragment is found:

ngOnInit() {
  this.router.events.subscribe(val => {
    if (val instanceof NavigationEnd) {
      let fragmentIdx = val.urlAfterRedirects.lastIndexOf('#');
      if (fragmentIdx >= 0 && fragmentIdx < val.urlAfterRedirects.length - 1) {
        let fragment = val.urlAfterRedirects.substring(fragmentIdx+1);
        console.log('fragment: ' + fragment);
        document.getElementById(fragment).scrollIntoView();
      }
    }
  })
}

In this approach I'm using document.getElementId to lookup an element to scroll into view. So, in this approach the URL fragment is also the element id. This is easily modified if you want to avoid using id's and instead look up elements by CSS class or otherwise.

Finally, I changed the settings in the main app module back to defaults with regards to scrolling, etc. This manual approach requires no non-default settings.

Now, I can visit different anchors and see the scrolling as I go back/forward in history. Hope it helps someone!

EDIT:

In order to reuse this snippet with multiple components I refactored this into its own service. This service has a single method that I call from the ngOnInit of any page/component where I want anchor scrolling.

Here's a sample service:

import { Injectable } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';

@Injectable({
  providedIn: 'any'
})
export class AnchorScrollService {

  constructor(private router: Router) { }

  listen(): Subscription {
    return this.router.events.subscribe(val => {
      // console.log(val);
      if (val instanceof NavigationEnd) {
        let fragmentIdx = val.urlAfterRedirects.lastIndexOf('#');
        if (fragmentIdx >= 0 && fragmentIdx < val.urlAfterRedirects.length - 1) {
          let fragment = val.urlAfterRedirects.substring(fragmentIdx+1);
          // console.log('fragment: ' + fragment);
          document.getElementById(fragment).scrollIntoView();
        }
      }
    })
  }
}

Note: the latest Chrome has a bug with anchor scrolling that I'm seeing on initial navigation. Subsequent navigation/history works and all is perfect in, say, Firefox. Worth noting though in case you are having Chrome frustrations...you're not alone!

Ardisardisj answered 21/6, 2020 at 1:35 Comment(1)
Thank you so much for sharing this, I was struggling with the same exact problem, and your answer worked perfectly for me :)Inesinescapable

© 2022 - 2024 — McMap. All rights reserved.