Angular2 Hashtag routing to Anchor doesnt move page

14,021

Solution 1

A workaround might be to write a function in your component that sets the location.hash to the id of the div you want to navigate to.

<a (click)="goTo('destination')">Go TO DIV</a>

<div id='destination'>
    <h2>Destination</h2>
</div>

Then in your component:

goTo(location: string): void {
    window.location.hash = location;
}

Solution 2

Here's a very simple solution that worked for me:

In the component, add this method:

navigateTo(location: string): void {
// location will be a valid CSS ID selector; i.e. it should be preceded with '#'
window.location.hash = location;
setTimeout(() => {
    document.querySelector(location).parentElement.scrollIntoView();
  });
}

And in the view, the <a> tag will look like this:

<a (click)="navigateTo('#destination')">Destination</a>

Solution 3

This workaround should do the trick

<div [routerLink]="[]" fragment="destination">
  <a href="#destination">Go TO DIV</a>
</div>

Solution 4

After seeing all the solutions here, I decided to go with a small and simple directive. Here's what I ended up with:

import { Directive, ElementRef, HostListener, Input } from '@angular/core';

@Directive({ selector: '[appAnchorTo]' })
export class AnchorToDirective {
  @Input() target: string;

  constructor(el: ElementRef) { el.nativeElement.style.cursor = 'pointer'; }

  @HostListener('click', ['$event'])
  onClick() { document.querySelector(this.target).scrollIntoView(); }
}

The idea was to create something flexible, that could be attached to any element on the page.

Usage:

<a appAnchorTo target="#my-link">My Insights</a>
<div appAnchorTo target="#my-other-link">My Customers</div>

And don't forget to declare the directive on one of your Modules:

@NgModule({
    ...,
    declarations: [
        ...,
        AnchorToDirective,
    ]
})

Solution 5

This worked for me:

First, prepare MyAppComponent for automatic scrolling in ngAfterViewChecked()...

import { Component, OnInit, AfterViewChecked } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';

@Component( {
   [...]
} )
export class MyAppComponent implements OnInit, AfterViewChecked {

  private scrollExecuted: boolean = false;

  constructor( private activatedRoute: ActivatedRoute ) {}

  ngAfterViewChecked() {

    if ( !this.scrollExecuted ) {
      let routeFragmentSubscription: Subscription;

      // Automatic scroll
      routeFragmentSubscription =
        this.activatedRoute.fragment
          .subscribe( fragment => {
            if ( fragment ) {
              let element = document.getElementById( fragment );
              if ( element ) {
                element.scrollIntoView();

                this.scrollExecuted = true;

                // Free resources
                setTimeout(
                  () => {
                    console.log( 'routeFragmentSubscription unsubscribe' );
                    routeFragmentSubscription.unsubscribe();
                }, 1000 );
              }
            }
          } );
    }

  }

}

Then, navigate to my-app-route sending prodID hashtag

import { Component } from '@angular/core';
import { Router } from '@angular/router';

@Component( {
   [...]
} )
export class MyOtherComponent {

  constructor( private router: Router ) {}

  gotoHashtag( prodID: string ) {
    this.router.navigate( [ '/my-app-route' ], { fragment: prodID } );
  }

}
Share:
14,021
jipson
Author by

jipson

Updated on June 28, 2022

Comments

  • jipson
    jipson almost 2 years

    So I used the following post to figure out how to add a fragment to the url.

    Angular2 Routing with Hashtag to page anchor

    And the fragment gets added fine, however the page doesn't move to the resulting anchor. I have tried using both the name and id attribute on the destination div, but neither seem to work.

    I'm using Angular Version 2.0.0-rc.3, and router version 3.0.0-alpha.6.

    Thanks!

    <a [routerLink]="[]" fragment="destination">Go TO DIV</a>
    
    <div id='destination'>
        <h2>Destination</h2>
    </div>
    

    There is enough space between the 2 elements to tell if the page actually moves.

    And as said before, the url correctly adds #destination to itself.

  • Samurai Girl
    Samurai Girl about 7 years
    I would add one note to this. It sets hash only once, so if the hash is already included in the page and you click on the same anchor link, it won't scroll to the destination. But it works if you clear the hash before setting -> window.location.hash = ''; window.location.hash = location;
  • JonathanPeel
    JonathanPeel about 7 years
    I tried this, it works, but then everything above the target disappears.
  • Mindsect Team
    Mindsect Team over 6 years
    Currently using Angular 4 / CLI. This was the BEST solution. Thank you! Also, simplest with smallest amount of code that actually worked.
  • Oliver
    Oliver over 6 years
    Thanks, no TypeScript/JavaScript needed!. This stuff shouldn't be so hard. Feel like the wheel's being reinvented sometimes.
  • Gilles
    Gilles over 6 years
    Far less complicated than using the router. I understand why this is complicated because of routing and all that SPA stuff, but anchor links are such a basic feature.
  • Daniel Kucal
    Daniel Kucal over 6 years
    It will not generate proper url on any path different than root.